Import stockfish_5.0.dd+git20140823.orig.tar.gz
authorOliver Korff <ok@xynyx.de>
Sat, 23 Aug 2014 14:43:44 +0000 (15:43 +0100)
committerOliver Korff <ok@xynyx.de>
Sat, 23 Aug 2014 14:43:44 +0000 (15:43 +0100)
[dgit import orig stockfish_5.0.dd+git20140823.orig.tar.gz]

42 files changed:
Copying.txt [new file with mode: 0644]
Readme.md [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/benchmark.cpp [new file with mode: 0644]
src/bitbase.cpp [new file with mode: 0644]
src/bitboard.cpp [new file with mode: 0644]
src/bitboard.h [new file with mode: 0644]
src/bitcount.h [new file with mode: 0644]
src/endgame.cpp [new file with mode: 0644]
src/endgame.h [new file with mode: 0644]
src/evaluate.cpp [new file with mode: 0644]
src/evaluate.h [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/material.cpp [new file with mode: 0644]
src/material.h [new file with mode: 0644]
src/misc.cpp [new file with mode: 0644]
src/misc.h [new file with mode: 0644]
src/movegen.cpp [new file with mode: 0644]
src/movegen.h [new file with mode: 0644]
src/movepick.cpp [new file with mode: 0644]
src/movepick.h [new file with mode: 0644]
src/notation.cpp [new file with mode: 0644]
src/notation.h [new file with mode: 0644]
src/pawns.cpp [new file with mode: 0644]
src/pawns.h [new file with mode: 0644]
src/platform.h [new file with mode: 0644]
src/position.cpp [new file with mode: 0644]
src/position.h [new file with mode: 0644]
src/psqtab.h [new file with mode: 0644]
src/rkiss.h [new file with mode: 0644]
src/search.cpp [new file with mode: 0644]
src/search.h [new file with mode: 0644]
src/thread.cpp [new file with mode: 0644]
src/thread.h [new file with mode: 0644]
src/timeman.cpp [new file with mode: 0644]
src/timeman.h [new file with mode: 0644]
src/tt.cpp [new file with mode: 0644]
src/tt.h [new file with mode: 0644]
src/types.h [new file with mode: 0644]
src/uci.cpp [new file with mode: 0644]
src/ucioption.cpp [new file with mode: 0644]
src/ucioption.h [new file with mode: 0644]

diff --git a/Copying.txt b/Copying.txt
new file mode 100644 (file)
index 0000000..818433e
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE\r
+                       Version 3, 29 June 2007\r
+\r
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+                            Preamble\r
+\r
+  The GNU General Public License is a free, copyleft license for\r
+software and other kinds of works.\r
+\r
+  The licenses for most software and other practical works are designed\r
+to take away your freedom to share and change the works.  By contrast,\r
+the GNU General Public License is intended to guarantee your freedom to\r
+share and change all versions of a program--to make sure it remains free\r
+software for all its users.  We, the Free Software Foundation, use the\r
+GNU General Public License for most of our software; it applies also to\r
+any other work released this way by its authors.  You can apply it to\r
+your programs, too.\r
+\r
+  When we speak of free software, we are referring to freedom, not\r
+price.  Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+them if you wish), that you receive source code or can get it if you\r
+want it, that you can change the software or use pieces of it in new\r
+free programs, and that you know you can do these things.\r
+\r
+  To protect your rights, we need to prevent others from denying you\r
+these rights or asking you to surrender the rights.  Therefore, you have\r
+certain responsibilities if you distribute copies of the software, or if\r
+you modify it: responsibilities to respect the freedom of others.\r
+\r
+  For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must pass on to the recipients the same\r
+freedoms that you received.  You must make sure that they, too, receive\r
+or can get the source code.  And you must show them these terms so they\r
+know their rights.\r
+\r
+  Developers that use the GNU GPL protect your rights with two steps:\r
+(1) assert copyright on the software, and (2) offer you this License\r
+giving you legal permission to copy, distribute and/or modify it.\r
+\r
+  For the developers' and authors' protection, the GPL clearly explains\r
+that there is no warranty for this free software.  For both users' and\r
+authors' sake, the GPL requires that modified versions be marked as\r
+changed, so that their problems will not be attributed erroneously to\r
+authors of previous versions.\r
+\r
+  Some devices are designed to deny users access to install or run\r
+modified versions of the software inside them, although the manufacturer\r
+can do so.  This is fundamentally incompatible with the aim of\r
+protecting users' freedom to change the software.  The systematic\r
+pattern of such abuse occurs in the area of products for individuals to\r
+use, which is precisely where it is most unacceptable.  Therefore, we\r
+have designed this version of the GPL to prohibit the practice for those\r
+products.  If such problems arise substantially in other domains, we\r
+stand ready to extend this provision to those domains in future versions\r
+of the GPL, as needed to protect the freedom of users.\r
+\r
+  Finally, every program is threatened constantly by software patents.\r
+States should not allow patents to restrict development and use of\r
+software on general-purpose computers, but in those that do, we wish to\r
+avoid the special danger that patents applied to a free program could\r
+make it effectively proprietary.  To prevent this, the GPL assures that\r
+patents cannot be used to render the program non-free.\r
+\r
+  The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+                       TERMS AND CONDITIONS\r
+\r
+  0. Definitions.\r
+\r
+  "This License" refers to version 3 of the GNU General Public License.\r
+\r
+  "Copyright" also means copyright-like laws that apply to other kinds of\r
+works, such as semiconductor masks.\r
+\r
+  "The Program" refers to any copyrightable work licensed under this\r
+License.  Each licensee is addressed as "you".  "Licensees" and\r
+"recipients" may be individuals or organizations.\r
+\r
+  To "modify" a work means to copy from or adapt all or part of the work\r
+in a fashion requiring copyright permission, other than the making of an\r
+exact copy.  The resulting work is called a "modified version" of the\r
+earlier work or a work "based on" the earlier work.\r
+\r
+  A "covered work" means either the unmodified Program or a work based\r
+on the Program.\r
+\r
+  To "propagate" a work means to do anything with it that, without\r
+permission, would make you directly or secondarily liable for\r
+infringement under applicable copyright law, except executing it on a\r
+computer or modifying a private copy.  Propagation includes copying,\r
+distribution (with or without modification), making available to the\r
+public, and in some countries other activities as well.\r
+\r
+  To "convey" a work means any kind of propagation that enables other\r
+parties to make or receive copies.  Mere interaction with a user through\r
+a computer network, with no transfer of a copy, is not conveying.\r
+\r
+  An interactive user interface displays "Appropriate Legal Notices"\r
+to the extent that it includes a convenient and prominently visible\r
+feature that (1) displays an appropriate copyright notice, and (2)\r
+tells the user that there is no warranty for the work (except to the\r
+extent that warranties are provided), that licensees may convey the\r
+work under this License, and how to view a copy of this License.  If\r
+the interface presents a list of user commands or options, such as a\r
+menu, a prominent item in the list meets this criterion.\r
+\r
+  1. Source Code.\r
+\r
+  The "source code" for a work means the preferred form of the work\r
+for making modifications to it.  "Object code" means any non-source\r
+form of a work.\r
+\r
+  A "Standard Interface" means an interface that either is an official\r
+standard defined by a recognized standards body, or, in the case of\r
+interfaces specified for a particular programming language, one that\r
+is widely used among developers working in that language.\r
+\r
+  The "System Libraries" of an executable work include anything, other\r
+than the work as a whole, that (a) is included in the normal form of\r
+packaging a Major Component, but which is not part of that Major\r
+Component, and (b) serves only to enable use of the work with that\r
+Major Component, or to implement a Standard Interface for which an\r
+implementation is available to the public in source code form.  A\r
+"Major Component", in this context, means a major essential component\r
+(kernel, window system, and so on) of the specific operating system\r
+(if any) on which the executable work runs, or a compiler used to\r
+produce the work, or an object code interpreter used to run it.\r
+\r
+  The "Corresponding Source" for a work in object code form means all\r
+the source code needed to generate, install, and (for an executable\r
+work) run the object code and to modify the work, including scripts to\r
+control those activities.  However, it does not include the work's\r
+System Libraries, or general-purpose tools or generally available free\r
+programs which are used unmodified in performing those activities but\r
+which are not part of the work.  For example, Corresponding Source\r
+includes interface definition files associated with source files for\r
+the work, and the source code for shared libraries and dynamically\r
+linked subprograms that the work is specifically designed to require,\r
+such as by intimate data communication or control flow between those\r
+subprograms and other parts of the work.\r
+\r
+  The Corresponding Source need not include anything that users\r
+can regenerate automatically from other parts of the Corresponding\r
+Source.\r
+\r
+  The Corresponding Source for a work in source code form is that\r
+same work.\r
+\r
+  2. Basic Permissions.\r
+\r
+  All rights granted under this License are granted for the term of\r
+copyright on the Program, and are irrevocable provided the stated\r
+conditions are met.  This License explicitly affirms your unlimited\r
+permission to run the unmodified Program.  The output from running a\r
+covered work is covered by this License only if the output, given its\r
+content, constitutes a covered work.  This License acknowledges your\r
+rights of fair use or other equivalent, as provided by copyright law.\r
+\r
+  You may make, run and propagate covered works that you do not\r
+convey, without conditions so long as your license otherwise remains\r
+in force.  You may convey covered works to others for the sole purpose\r
+of having them make modifications exclusively for you, or provide you\r
+with facilities for running those works, provided that you comply with\r
+the terms of this License in conveying all material for which you do\r
+not control copyright.  Those thus making or running the covered works\r
+for you must do so exclusively on your behalf, under your direction\r
+and control, on terms that prohibit them from making any copies of\r
+your copyrighted material outside their relationship with you.\r
+\r
+  Conveying under any other circumstances is permitted solely under\r
+the conditions stated below.  Sublicensing is not allowed; section 10\r
+makes it unnecessary.\r
+\r
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\r
+\r
+  No covered work shall be deemed part of an effective technological\r
+measure under any applicable law fulfilling obligations under article\r
+11 of the WIPO copyright treaty adopted on 20 December 1996, or\r
+similar laws prohibiting or restricting circumvention of such\r
+measures.\r
+\r
+  When you convey a covered work, you waive any legal power to forbid\r
+circumvention of technological measures to the extent such circumvention\r
+is effected by exercising rights under this License with respect to\r
+the covered work, and you disclaim any intention to limit operation or\r
+modification of the work as a means of enforcing, against the work's\r
+users, your or third parties' legal rights to forbid circumvention of\r
+technological measures.\r
+\r
+  4. Conveying Verbatim Copies.\r
+\r
+  You may convey verbatim copies of the Program's source code as you\r
+receive it, in any medium, provided that you conspicuously and\r
+appropriately publish on each copy an appropriate copyright notice;\r
+keep intact all notices stating that this License and any\r
+non-permissive terms added in accord with section 7 apply to the code;\r
+keep intact all notices of the absence of any warranty; and give all\r
+recipients a copy of this License along with the Program.\r
+\r
+  You may charge any price or no price for each copy that you convey,\r
+and you may offer support or warranty protection for a fee.\r
+\r
+  5. Conveying Modified Source Versions.\r
+\r
+  You may convey a work based on the Program, or the modifications to\r
+produce it from the Program, in the form of source code under the\r
+terms of section 4, provided that you also meet all of these conditions:\r
+\r
+    a) The work must carry prominent notices stating that you modified\r
+    it, and giving a relevant date.\r
+\r
+    b) The work must carry prominent notices stating that it is\r
+    released under this License and any conditions added under section\r
+    7.  This requirement modifies the requirement in section 4 to\r
+    "keep intact all notices".\r
+\r
+    c) You must license the entire work, as a whole, under this\r
+    License to anyone who comes into possession of a copy.  This\r
+    License will therefore apply, along with any applicable section 7\r
+    additional terms, to the whole of the work, and all its parts,\r
+    regardless of how they are packaged.  This License gives no\r
+    permission to license the work in any other way, but it does not\r
+    invalidate such permission if you have separately received it.\r
+\r
+    d) If the work has interactive user interfaces, each must display\r
+    Appropriate Legal Notices; however, if the Program has interactive\r
+    interfaces that do not display Appropriate Legal Notices, your\r
+    work need not make them do so.\r
+\r
+  A compilation of a covered work with other separate and independent\r
+works, which are not by their nature extensions of the covered work,\r
+and which are not combined with it such as to form a larger program,\r
+in or on a volume of a storage or distribution medium, is called an\r
+"aggregate" if the compilation and its resulting copyright are not\r
+used to limit the access or legal rights of the compilation's users\r
+beyond what the individual works permit.  Inclusion of a covered work\r
+in an aggregate does not cause this License to apply to the other\r
+parts of the aggregate.\r
+\r
+  6. Conveying Non-Source Forms.\r
+\r
+  You may convey a covered work in object code form under the terms\r
+of sections 4 and 5, provided that you also convey the\r
+machine-readable Corresponding Source under the terms of this License,\r
+in one of these ways:\r
+\r
+    a) Convey the object code in, or embodied in, a physical product\r
+    (including a physical distribution medium), accompanied by the\r
+    Corresponding Source fixed on a durable physical medium\r
+    customarily used for software interchange.\r
+\r
+    b) Convey the object code in, or embodied in, a physical product\r
+    (including a physical distribution medium), accompanied by a\r
+    written offer, valid for at least three years and valid for as\r
+    long as you offer spare parts or customer support for that product\r
+    model, to give anyone who possesses the object code either (1) a\r
+    copy of the Corresponding Source for all the software in the\r
+    product that is covered by this License, on a durable physical\r
+    medium customarily used for software interchange, for a price no\r
+    more than your reasonable cost of physically performing this\r
+    conveying of source, or (2) access to copy the\r
+    Corresponding Source from a network server at no charge.\r
+\r
+    c) Convey individual copies of the object code with a copy of the\r
+    written offer to provide the Corresponding Source.  This\r
+    alternative is allowed only occasionally and noncommercially, and\r
+    only if you received the object code with such an offer, in accord\r
+    with subsection 6b.\r
+\r
+    d) Convey the object code by offering access from a designated\r
+    place (gratis or for a charge), and offer equivalent access to the\r
+    Corresponding Source in the same way through the same place at no\r
+    further charge.  You need not require recipients to copy the\r
+    Corresponding Source along with the object code.  If the place to\r
+    copy the object code is a network server, the Corresponding Source\r
+    may be on a different server (operated by you or a third party)\r
+    that supports equivalent copying facilities, provided you maintain\r
+    clear directions next to the object code saying where to find the\r
+    Corresponding Source.  Regardless of what server hosts the\r
+    Corresponding Source, you remain obligated to ensure that it is\r
+    available for as long as needed to satisfy these requirements.\r
+\r
+    e) Convey the object code using peer-to-peer transmission, provided\r
+    you inform other peers where the object code and Corresponding\r
+    Source of the work are being offered to the general public at no\r
+    charge under subsection 6d.\r
+\r
+  A separable portion of the object code, whose source code is excluded\r
+from the Corresponding Source as a System Library, need not be\r
+included in conveying the object code work.\r
+\r
+  A "User Product" is either (1) a "consumer product", which means any\r
+tangible personal property which is normally used for personal, family,\r
+or household purposes, or (2) anything designed or sold for incorporation\r
+into a dwelling.  In determining whether a product is a consumer product,\r
+doubtful cases shall be resolved in favor of coverage.  For a particular\r
+product received by a particular user, "normally used" refers to a\r
+typical or common use of that class of product, regardless of the status\r
+of the particular user or of the way in which the particular user\r
+actually uses, or expects or is expected to use, the product.  A product\r
+is a consumer product regardless of whether the product has substantial\r
+commercial, industrial or non-consumer uses, unless such uses represent\r
+the only significant mode of use of the product.\r
+\r
+  "Installation Information" for a User Product means any methods,\r
+procedures, authorization keys, or other information required to install\r
+and execute modified versions of a covered work in that User Product from\r
+a modified version of its Corresponding Source.  The information must\r
+suffice to ensure that the continued functioning of the modified object\r
+code is in no case prevented or interfered with solely because\r
+modification has been made.\r
+\r
+  If you convey an object code work under this section in, or with, or\r
+specifically for use in, a User Product, and the conveying occurs as\r
+part of a transaction in which the right of possession and use of the\r
+User Product is transferred to the recipient in perpetuity or for a\r
+fixed term (regardless of how the transaction is characterized), the\r
+Corresponding Source conveyed under this section must be accompanied\r
+by the Installation Information.  But this requirement does not apply\r
+if neither you nor any third party retains the ability to install\r
+modified object code on the User Product (for example, the work has\r
+been installed in ROM).\r
+\r
+  The requirement to provide Installation Information does not include a\r
+requirement to continue to provide support service, warranty, or updates\r
+for a work that has been modified or installed by the recipient, or for\r
+the User Product in which it has been modified or installed.  Access to a\r
+network may be denied when the modification itself materially and\r
+adversely affects the operation of the network or violates the rules and\r
+protocols for communication across the network.\r
+\r
+  Corresponding Source conveyed, and Installation Information provided,\r
+in accord with this section must be in a format that is publicly\r
+documented (and with an implementation available to the public in\r
+source code form), and must require no special password or key for\r
+unpacking, reading or copying.\r
+\r
+  7. Additional Terms.\r
+\r
+  "Additional permissions" are terms that supplement the terms of this\r
+License by making exceptions from one or more of its conditions.\r
+Additional permissions that are applicable to the entire Program shall\r
+be treated as though they were included in this License, to the extent\r
+that they are valid under applicable law.  If additional permissions\r
+apply only to part of the Program, that part may be used separately\r
+under those permissions, but the entire Program remains governed by\r
+this License without regard to the additional permissions.\r
+\r
+  When you convey a copy of a covered work, you may at your option\r
+remove any additional permissions from that copy, or from any part of\r
+it.  (Additional permissions may be written to require their own\r
+removal in certain cases when you modify the work.)  You may place\r
+additional permissions on material, added by you to a covered work,\r
+for which you have or can give appropriate copyright permission.\r
+\r
+  Notwithstanding any other provision of this License, for material you\r
+add to a covered work, you may (if authorized by the copyright holders of\r
+that material) supplement the terms of this License with terms:\r
+\r
+    a) Disclaiming warranty or limiting liability differently from the\r
+    terms of sections 15 and 16 of this License; or\r
+\r
+    b) Requiring preservation of specified reasonable legal notices or\r
+    author attributions in that material or in the Appropriate Legal\r
+    Notices displayed by works containing it; or\r
+\r
+    c) Prohibiting misrepresentation of the origin of that material, or\r
+    requiring that modified versions of such material be marked in\r
+    reasonable ways as different from the original version; or\r
+\r
+    d) Limiting the use for publicity purposes of names of licensors or\r
+    authors of the material; or\r
+\r
+    e) Declining to grant rights under trademark law for use of some\r
+    trade names, trademarks, or service marks; or\r
+\r
+    f) Requiring indemnification of licensors and authors of that\r
+    material by anyone who conveys the material (or modified versions of\r
+    it) with contractual assumptions of liability to the recipient, for\r
+    any liability that these contractual assumptions directly impose on\r
+    those licensors and authors.\r
+\r
+  All other non-permissive additional terms are considered "further\r
+restrictions" within the meaning of section 10.  If the Program as you\r
+received it, or any part of it, contains a notice stating that it is\r
+governed by this License along with a term that is a further\r
+restriction, you may remove that term.  If a license document contains\r
+a further restriction but permits relicensing or conveying under this\r
+License, you may add to a covered work material governed by the terms\r
+of that license document, provided that the further restriction does\r
+not survive such relicensing or conveying.\r
+\r
+  If you add terms to a covered work in accord with this section, you\r
+must place, in the relevant source files, a statement of the\r
+additional terms that apply to those files, or a notice indicating\r
+where to find the applicable terms.\r
+\r
+  Additional terms, permissive or non-permissive, may be stated in the\r
+form of a separately written license, or stated as exceptions;\r
+the above requirements apply either way.\r
+\r
+  8. Termination.\r
+\r
+  You may not propagate or modify a covered work except as expressly\r
+provided under this License.  Any attempt otherwise to propagate or\r
+modify it is void, and will automatically terminate your rights under\r
+this License (including any patent licenses granted under the third\r
+paragraph of section 11).\r
+\r
+  However, if you cease all violation of this License, then your\r
+license from a particular copyright holder is reinstated (a)\r
+provisionally, unless and until the copyright holder explicitly and\r
+finally terminates your license, and (b) permanently, if the copyright\r
+holder fails to notify you of the violation by some reasonable means\r
+prior to 60 days after the cessation.\r
+\r
+  Moreover, your license from a particular copyright holder is\r
+reinstated permanently if the copyright holder notifies you of the\r
+violation by some reasonable means, this is the first time you have\r
+received notice of violation of this License (for any work) from that\r
+copyright holder, and you cure the violation prior to 30 days after\r
+your receipt of the notice.\r
+\r
+  Termination of your rights under this section does not terminate the\r
+licenses of parties who have received copies or rights from you under\r
+this License.  If your rights have been terminated and not permanently\r
+reinstated, you do not qualify to receive new licenses for the same\r
+material under section 10.\r
+\r
+  9. Acceptance Not Required for Having Copies.\r
+\r
+  You are not required to accept this License in order to receive or\r
+run a copy of the Program.  Ancillary propagation of a covered work\r
+occurring solely as a consequence of using peer-to-peer transmission\r
+to receive a copy likewise does not require acceptance.  However,\r
+nothing other than this License grants you permission to propagate or\r
+modify any covered work.  These actions infringe copyright if you do\r
+not accept this License.  Therefore, by modifying or propagating a\r
+covered work, you indicate your acceptance of this License to do so.\r
+\r
+  10. Automatic Licensing of Downstream Recipients.\r
+\r
+  Each time you convey a covered work, the recipient automatically\r
+receives a license from the original licensors, to run, modify and\r
+propagate that work, subject to this License.  You are not responsible\r
+for enforcing compliance by third parties with this License.\r
+\r
+  An "entity transaction" is a transaction transferring control of an\r
+organization, or substantially all assets of one, or subdividing an\r
+organization, or merging organizations.  If propagation of a covered\r
+work results from an entity transaction, each party to that\r
+transaction who receives a copy of the work also receives whatever\r
+licenses to the work the party's predecessor in interest had or could\r
+give under the previous paragraph, plus a right to possession of the\r
+Corresponding Source of the work from the predecessor in interest, if\r
+the predecessor has it or can get it with reasonable efforts.\r
+\r
+  You may not impose any further restrictions on the exercise of the\r
+rights granted or affirmed under this License.  For example, you may\r
+not impose a license fee, royalty, or other charge for exercise of\r
+rights granted under this License, and you may not initiate litigation\r
+(including a cross-claim or counterclaim in a lawsuit) alleging that\r
+any patent claim is infringed by making, using, selling, offering for\r
+sale, or importing the Program or any portion of it.\r
+\r
+  11. Patents.\r
+\r
+  A "contributor" is a copyright holder who authorizes use under this\r
+License of the Program or a work on which the Program is based.  The\r
+work thus licensed is called the contributor's "contributor version".\r
+\r
+  A contributor's "essential patent claims" are all patent claims\r
+owned or controlled by the contributor, whether already acquired or\r
+hereafter acquired, that would be infringed by some manner, permitted\r
+by this License, of making, using, or selling its contributor version,\r
+but do not include claims that would be infringed only as a\r
+consequence of further modification of the contributor version.  For\r
+purposes of this definition, "control" includes the right to grant\r
+patent sublicenses in a manner consistent with the requirements of\r
+this License.\r
+\r
+  Each contributor grants you a non-exclusive, worldwide, royalty-free\r
+patent license under the contributor's essential patent claims, to\r
+make, use, sell, offer for sale, import and otherwise run, modify and\r
+propagate the contents of its contributor version.\r
+\r
+  In the following three paragraphs, a "patent license" is any express\r
+agreement or commitment, however denominated, not to enforce a patent\r
+(such as an express permission to practice a patent or covenant not to\r
+sue for patent infringement).  To "grant" such a patent license to a\r
+party means to make such an agreement or commitment not to enforce a\r
+patent against the party.\r
+\r
+  If you convey a covered work, knowingly relying on a patent license,\r
+and the Corresponding Source of the work is not available for anyone\r
+to copy, free of charge and under the terms of this License, through a\r
+publicly available network server or other readily accessible means,\r
+then you must either (1) cause the Corresponding Source to be so\r
+available, or (2) arrange to deprive yourself of the benefit of the\r
+patent license for this particular work, or (3) arrange, in a manner\r
+consistent with the requirements of this License, to extend the patent\r
+license to downstream recipients.  "Knowingly relying" means you have\r
+actual knowledge that, but for the patent license, your conveying the\r
+covered work in a country, or your recipient's use of the covered work\r
+in a country, would infringe one or more identifiable patents in that\r
+country that you have reason to believe are valid.\r
+\r
+  If, pursuant to or in connection with a single transaction or\r
+arrangement, you convey, or propagate by procuring conveyance of, a\r
+covered work, and grant a patent license to some of the parties\r
+receiving the covered work authorizing them to use, propagate, modify\r
+or convey a specific copy of the covered work, then the patent license\r
+you grant is automatically extended to all recipients of the covered\r
+work and works based on it.\r
+\r
+  A patent license is "discriminatory" if it does not include within\r
+the scope of its coverage, prohibits the exercise of, or is\r
+conditioned on the non-exercise of one or more of the rights that are\r
+specifically granted under this License.  You may not convey a covered\r
+work if you are a party to an arrangement with a third party that is\r
+in the business of distributing software, under which you make payment\r
+to the third party based on the extent of your activity of conveying\r
+the work, and under which the third party grants, to any of the\r
+parties who would receive the covered work from you, a discriminatory\r
+patent license (a) in connection with copies of the covered work\r
+conveyed by you (or copies made from those copies), or (b) primarily\r
+for and in connection with specific products or compilations that\r
+contain the covered work, unless you entered into that arrangement,\r
+or that patent license was granted, prior to 28 March 2007.\r
+\r
+  Nothing in this License shall be construed as excluding or limiting\r
+any implied license or other defenses to infringement that may\r
+otherwise be available to you under applicable patent law.\r
+\r
+  12. No Surrender of Others' Freedom.\r
+\r
+  If conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License.  If you cannot convey a\r
+covered work so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you may\r
+not convey it at all.  For example, if you agree to terms that obligate you\r
+to collect a royalty for further conveying from those to whom you convey\r
+the Program, the only way you could satisfy both those terms and this\r
+License would be to refrain entirely from conveying the Program.\r
+\r
+  13. Use with the GNU Affero General Public License.\r
+\r
+  Notwithstanding any other provision of this License, you have\r
+permission to link or combine any covered work with a work licensed\r
+under version 3 of the GNU Affero General Public License into a single\r
+combined work, and to convey the resulting work.  The terms of this\r
+License will continue to apply to the part which is the covered work,\r
+but the special requirements of the GNU Affero General Public License,\r
+section 13, concerning interaction through a network will apply to the\r
+combination as such.\r
+\r
+  14. Revised Versions of this License.\r
+\r
+  The Free Software Foundation may publish revised and/or new versions of\r
+the GNU General Public License from time to time.  Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+  Each version is given a distinguishing version number.  If the\r
+Program specifies that a certain numbered version of the GNU General\r
+Public License "or any later version" applies to it, you have the\r
+option of following the terms and conditions either of that numbered\r
+version or of any later version published by the Free Software\r
+Foundation.  If the Program does not specify a version number of the\r
+GNU General Public License, you may choose any version ever published\r
+by the Free Software Foundation.\r
+\r
+  If the Program specifies that a proxy can decide which future\r
+versions of the GNU General Public License can be used, that proxy's\r
+public statement of acceptance of a version permanently authorizes you\r
+to choose that version for the Program.\r
+\r
+  Later license versions may give you additional or different\r
+permissions.  However, no additional obligations are imposed on any\r
+author or copyright holder as a result of your choosing to follow a\r
+later version.\r
+\r
+  15. Disclaimer of Warranty.\r
+\r
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\r
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\r
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\r
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\r
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\r
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\r
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
+\r
+  16. Limitation of Liability.\r
+\r
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\r
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\r
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\r
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\r
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\r
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\r
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGES.\r
+\r
+  17. Interpretation of Sections 15 and 16.\r
+\r
+  If the disclaimer of warranty and limitation of liability provided\r
+above cannot be given local legal effect according to their terms,\r
+reviewing courts shall apply local law that most closely approximates\r
+an absolute waiver of all civil liability in connection with the\r
+Program, unless a warranty or assumption of liability accompanies a\r
+copy of the Program in return for a fee.\r
+\r
+                     END OF TERMS AND CONDITIONS\r
+\r
+            How to Apply These Terms to Your New Programs\r
+\r
+  If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+  To do so, attach the following notices to the program.  It is safest\r
+to attach them to the start of each source file to most effectively\r
+state the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+    <one line to give the program's name and a brief idea of what it does.>\r
+    Copyright (C) <year>  <name of author>\r
+\r
+    This program is free software: you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation, either version 3 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+  If the program does terminal interaction, make it output a short\r
+notice like this when it starts in an interactive mode:\r
+\r
+    <program>  Copyright (C) <year>  <name of author>\r
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+    This is free software, and you are welcome to redistribute it\r
+    under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License.  Of course, your program's commands\r
+might be different; for a GUI interface, you would use an "about box".\r
+\r
+  You should also get your employer (if you work as a programmer) or school,\r
+if any, to sign a "copyright disclaimer" for the program, if necessary.\r
+For more information on this, and how to apply and follow the GNU GPL, see\r
+<http://www.gnu.org/licenses/>.\r
+\r
+  The GNU General Public License does not permit incorporating your program\r
+into proprietary programs.  If your program is a subroutine library, you\r
+may consider it more useful to permit linking proprietary applications with\r
+the library.  If this is what you want to do, use the GNU Lesser General\r
+Public License instead of this License.  But first, please read\r
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.\r
diff --git a/Readme.md b/Readme.md
new file mode 100644 (file)
index 0000000..d4ea7a0
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,58 @@
+### Overview
+
+Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
+not a complete chess program and requires some UCI-compatible GUI
+(e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
+Partner or Fritz) in order to be used comfortably. Read the
+documentation for your GUI of choice for information about how to use
+Stockfish with it.
+
+This version of Stockfish supports up to 128 cores. The engine defaults
+to one search thread, so it is therefore recommended to inspect the value of
+the *Threads* UCI parameter, and to make sure it equals the number of CPU
+cores on your computer.
+
+
+### Files
+
+This distribution of Stockfish consists of the following files:
+
+  * Readme.md, the file you are currently reading.
+
+  * Copying.txt, a text file containing the GNU General Public License.
+
+  * src, a subdirectory containing the full source code, including a Makefile
+    that can be used to compile Stockfish on Unix-like systems.
+
+
+### Compiling it yourself
+
+On Unix-like systems, it should be possible to compile Stockfish
+directly from the source code with the included Makefile.
+
+Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT
+instruction, big-endian machines such as Power PC, and other platforms.
+
+In general it is recommended to run `make help` to see a list of make
+targets with corresponding descriptions. When not using the Makefile to
+compile (for instance with Microsoft MSVC) you need to manually
+set/unset some switches in the compiler command line; see file *types.h*
+for a quick reference.
+
+
+### Terms of use
+
+Stockfish is free, and distributed under the **GNU General Public License**
+(GPL). Essentially, this means that you are free to do almost exactly
+what you want with the program, including distributing it among your
+friends, making it available for download from your web site, selling
+it (either by itself or as part of some bigger software package), or
+using it as the starting point for a software project of your own.
+
+The only real limitation is that whenever you distribute Stockfish in
+some way, you must always include the full source code, or a pointer
+to where the source code can be found. If you make any changes to the
+source code, these changes must also be made available under the GPL.
+
+For full details, read the copy of the GPL found in the file named
+*Copying.txt*
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..187e7b3
--- /dev/null
@@ -0,0 +1,496 @@
+# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+# Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+#
+# Stockfish is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Stockfish is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+### ==========================================================================
+### Section 1. General Configuration
+### ==========================================================================
+
+### Establish the operating system name
+UNAME = $(shell uname)
+
+### Executable name
+EXE = stockfish
+
+### Installation dir definitions
+PREFIX = /usr/local
+# Haiku has a non-standard filesystem layout
+ifeq ($(UNAME),Haiku)
+       PREFIX=/boot/system/non-packaged
+endif
+BINDIR = $(PREFIX)/bin
+
+### Built-in benchmark for pgo-builds
+PGOBENCH = ./$(EXE) bench 32 1 1 default time
+
+### Object files
+OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
+       material.o misc.o movegen.o movepick.o notation.o pawns.o \
+       position.o search.o thread.o timeman.o tt.o uci.o ucioption.o
+
+### ==========================================================================
+### Section 2. High-level Configuration
+### ==========================================================================
+#
+# flag                --- Comp switch --- Description
+# ----------------------------------------------------------------------------
+#
+# debug = yes/no      --- -DNDEBUG         --- Enable/Disable debug mode
+# optimize = yes/no   --- (-O3/-fast etc.) --- Enable/Disable optimizations
+# arch = (name)       --- (-arch)          --- Target architecture
+# os = (name)         ---                  --- Target operating system
+# bits = 64/32        --- -DIS_64BIT       --- 64-/32-bit operating system
+# prefetch = yes/no   --- -DUSE_PREFETCH   --- Use prefetch x86 asm-instruction
+# bsfq = yes/no       --- -DUSE_BSFQ       --- Use bsfq x86_64 asm-instruction (only
+#                                              with GCC and ICC 64-bit)
+# popcnt = yes/no     --- -DUSE_POPCNT     --- Use popcnt x86_64 asm-instruction
+# sse = yes/no        --- -msse            --- Use Intel Streaming SIMD Extensions
+# pext = yes/no       --- -DUSE_PEXT       --- Use pext x86_64 asm-instruction
+#
+# Note that Makefile is space sensitive, so when adding new architectures
+# or modifying existing flags, you have to make sure there are no extra spaces
+# at the end of the line for flag values.
+
+### 2.1. General and architecture defaults
+optimize = yes
+debug = no
+os = any
+bits = 32
+prefetch = no
+bsfq = no
+popcnt = no
+sse = no
+pext = no
+
+### 2.2 Architecture specific
+
+ifeq ($(ARCH),general-32)
+       arch = any
+endif
+
+ifeq ($(ARCH),x86-32-old)
+       arch = i386
+endif
+
+ifeq ($(ARCH),x86-32)
+       arch = i386
+       prefetch = yes
+       sse = yes
+endif
+
+ifeq ($(ARCH),general-64)
+       arch = any
+       bits = 64
+endif
+
+ifeq ($(ARCH),x86-64)
+       arch = x86_64
+       bits = 64
+       prefetch = yes
+       bsfq = yes
+       sse = yes
+endif
+
+ifeq ($(ARCH),x86-64-modern)
+       arch = x86_64
+       bits = 64
+       prefetch = yes
+       bsfq = yes
+       popcnt = yes
+       sse = yes
+endif
+
+ifeq ($(ARCH),x86-64-bmi2)
+       arch = x86_64
+       bits = 64
+       prefetch = yes
+       bsfq = yes
+       popcnt = yes
+       sse = yes
+       pext = yes
+endif
+
+ifeq ($(ARCH),armv7)
+       arch = armv7
+       prefetch = yes
+       bsfq = yes
+endif
+
+ifeq ($(ARCH),ppc-32)
+       arch = ppc
+endif
+
+ifeq ($(ARCH),ppc-64)
+       arch = ppc64
+       bits = 64
+endif
+
+
+### ==========================================================================
+### Section 3. Low-level configuration
+### ==========================================================================
+
+### 3.1 Selecting compiler (default = gcc)
+
+CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
+LDFLAGS += $(EXTRALDFLAGS)
+
+ifeq ($(COMP),)
+       COMP=gcc
+endif
+
+ifeq ($(COMP),gcc)
+       comp=gcc
+       CXX=g++
+       CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
+endif
+
+ifeq ($(COMP),mingw)
+       comp=mingw
+       CXX=g++
+       CXXFLAGS += -Wextra -Wshadow
+       LDFLAGS += -static-libstdc++ -static-libgcc
+endif
+
+ifeq ($(COMP),icc)
+       comp=icc
+       CXX=icpc
+       CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi
+endif
+
+ifeq ($(COMP),clang)
+       comp=clang
+       CXX=clang++
+       CXXFLAGS += -pedantic -Wno-long-long -Wextra -Wshadow
+endif
+
+ifeq ($(comp),icc)
+       profile_prepare = icc-profile-prepare
+       profile_make = icc-profile-make
+       profile_use = icc-profile-use
+       profile_clean = icc-profile-clean
+else
+       profile_prepare = gcc-profile-prepare
+       profile_make = gcc-profile-make
+       profile_use = gcc-profile-use
+       profile_clean = gcc-profile-clean
+endif
+
+ifeq ($(UNAME),Darwin)
+       CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.6
+       LDFLAGS += -arch $(arch) -mmacosx-version-min=10.6
+endif
+
+### On mingw use Windows threads, otherwise POSIX
+ifneq ($(comp),mingw)
+       # On Android Bionic's C library comes with its own pthread implementation bundled in
+       ifneq ($(arch),armv7)
+               # Haiku has pthreads in its libroot, so only link it in on other platforms
+               ifneq ($(UNAME),Haiku)
+                       LDFLAGS += -lpthread
+               endif
+       endif
+endif
+
+### 3.4 Debugging
+ifeq ($(debug),no)
+       CXXFLAGS += -DNDEBUG
+else
+       CXXFLAGS += -g
+endif
+
+### 3.5 Optimization
+ifeq ($(optimize),yes)
+
+       ifeq ($(comp),gcc)
+               CXXFLAGS += -O3
+
+               ifeq ($(UNAME),Darwin)
+                       ifeq ($(arch),i386)
+                               CXXFLAGS += -mdynamic-no-pic
+                       endif
+                       ifeq ($(arch),x86_64)
+                               CXXFLAGS += -mdynamic-no-pic
+                       endif
+               endif
+
+               ifeq ($(arch),armv7)
+                       CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
+               endif
+       endif
+
+       ifeq ($(comp),mingw)
+               CXXFLAGS += -O3
+       endif
+
+       ifeq ($(comp),icc)
+               ifeq ($(UNAME),Darwin)
+                       CXXFLAGS += -fast -mdynamic-no-pic
+               else
+                       CXXFLAGS += -fast
+               endif
+       endif
+
+       ifeq ($(comp),clang)
+               CXXFLAGS += -O3
+
+               ifeq ($(UNAME),Darwin)
+                       ifeq ($(pext),no)
+                               CXXFLAGS += -flto
+                               LDFLAGS += $(CXXFLAGS)
+                       endif
+                       ifeq ($(arch),i386)
+                               CXXFLAGS += -mdynamic-no-pic
+                       endif
+                       ifeq ($(arch),x86_64)
+                               CXXFLAGS += -mdynamic-no-pic
+                       endif
+               endif
+       endif
+endif
+
+### 3.6. Bits
+ifeq ($(bits),64)
+       CXXFLAGS += -DIS_64BIT
+endif
+
+### 3.7 prefetch
+ifeq ($(prefetch),yes)
+       ifeq ($(sse),yes)
+               CXXFLAGS += -msse
+               DEPENDFLAGS += -msse
+       endif
+else
+       CXXFLAGS += -DNO_PREFETCH
+endif
+
+### 3.8 bsfq
+ifeq ($(bsfq),yes)
+       CXXFLAGS += -DUSE_BSFQ
+endif
+
+### 3.9 popcnt
+ifeq ($(popcnt),yes)
+       CXXFLAGS += -msse3 -DUSE_POPCNT
+endif
+
+### 3.10 pext
+ifeq ($(pext),yes)
+       CXXFLAGS += -DUSE_PEXT
+       ifeq ($(comp),$(filter $(comp),gcc clang mingw))
+               CXXFLAGS += -mbmi -mbmi2
+       endif
+endif
+
+### 3.11 Link Time Optimization, it works since gcc 4.5 but not on mingw.
+### This is a mix of compile and link time options because the lto link phase
+### needs access to the optimization flags.
+ifeq ($(comp),gcc)
+       ifeq ($(optimize),yes)
+       ifeq ($(debug),no)
+               GCC_MAJOR := `$(CXX) -dumpversion | cut -f1 -d.`
+               GCC_MINOR := `$(CXX) -dumpversion | cut -f2 -d.`
+               ifeq (1,$(shell expr \( $(GCC_MAJOR) \> 4 \) \| \( $(GCC_MAJOR) \= 4 \& $(GCC_MINOR) \>= 5 \)))
+                       CXXFLAGS += -flto
+                       LDFLAGS += $(CXXFLAGS)
+               endif
+       endif
+       endif
+endif
+
+### ==========================================================================
+### Section 4. Public targets
+### ==========================================================================
+
+help:
+       @echo ""
+       @echo "To compile stockfish, type: "
+       @echo ""
+       @echo "make target ARCH=arch [COMP=comp]"
+       @echo ""
+       @echo "Supported targets:"
+       @echo ""
+       @echo "build                   > Standard build"
+       @echo "profile-build           > PGO build"
+       @echo "strip                   > Strip executable"
+       @echo "install                 > Install executable"
+       @echo "clean                   > Clean up"
+       @echo ""
+       @echo "Supported archs:"
+       @echo ""
+       @echo "x86-64                  > x86 64-bit"
+       @echo "x86-64-modern           > x86 64-bit with popcnt support"
+       @echo "x86-64-bmi2             > x86 64-bit with pext support"
+       @echo "x86-32                  > x86 32-bit with SSE support"
+       @echo "x86-32-old              > x86 32-bit fall back for old hardware"
+       @echo "ppc-64                  > PPC 64-bit"
+       @echo "ppc-32                  > PPC 32-bit"
+       @echo "armv7                   > ARMv7 32-bit"
+       @echo "general-64              > unspecified 64-bit"
+       @echo "general-32              > unspecified 32-bit"
+       @echo ""
+       @echo "Supported compilers:"
+       @echo ""
+       @echo "gcc                     > Gnu compiler (default)"
+       @echo "mingw                   > Gnu compiler with MinGW under Windows"
+       @echo "clang                   > LLVM Clang compiler"
+       @echo "icc                     > Intel compiler"
+       @echo ""
+       @echo "Non-standard targets:"
+       @echo ""
+       @echo "make hpux               >  Compile for HP-UX. Compiler = aCC"
+       @echo ""
+       @echo "Examples. If you don't know what to do, you likely want to run: "
+       @echo ""
+       @echo "make build ARCH=x86-64    (This is for 64-bit systems)"
+       @echo "make build ARCH=x86-32    (This is for 32-bit systems)"
+       @echo ""
+
+.PHONY: build profile-build
+build:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
+
+profile-build:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
+       @echo ""
+       @echo "Step 0/4. Preparing for profile build."
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
+       @echo ""
+       @echo "Step 1/4. Building executable for benchmark ..."
+       @touch *.cpp *.h
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
+       @echo ""
+       @echo "Step 2/4. Running benchmark for pgo-build ..."
+       @$(PGOBENCH) > /dev/null
+       @echo ""
+       @echo "Step 3/4. Building final executable ..."
+       @touch *.cpp
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
+       @echo ""
+       @echo "Step 4/4. Deleting profile data ..."
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
+
+strip:
+       strip $(EXE)
+
+install:
+       -mkdir -p -m 755 $(BINDIR)
+       -cp $(EXE) $(BINDIR)
+       -strip $(BINDIR)/$(EXE)
+
+clean:
+       $(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda
+
+default:
+       help
+
+### ==========================================================================
+### Section 5. Private targets
+### ==========================================================================
+
+all: $(EXE) .depend
+
+config-sanity:
+       @echo ""
+       @echo "Config:"
+       @echo "debug: '$(debug)'"
+       @echo "optimize: '$(optimize)'"
+       @echo "arch: '$(arch)'"
+       @echo "os: '$(os)'"
+       @echo "bits: '$(bits)'"
+       @echo "prefetch: '$(prefetch)'"
+       @echo "bsfq: '$(bsfq)'"
+       @echo "popcnt: '$(popcnt)'"
+       @echo "sse: '$(sse)'"
+       @echo "pext: '$(pext)'"
+       @echo ""
+       @echo "Flags:"
+       @echo "CXX: $(CXX)"
+       @echo "CXXFLAGS: $(CXXFLAGS)"
+       @echo "LDFLAGS: $(LDFLAGS)"
+       @echo ""
+       @echo "Testing config sanity. If this fails, try 'make help' ..."
+       @echo ""
+       @test "$(debug)" = "yes" || test "$(debug)" = "no"
+       @test "$(optimize)" = "yes" || test "$(optimize)" = "no"
+       @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
+        test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
+       @test "$(os)" = "any"
+       @test "$(bits)" = "32" || test "$(bits)" = "64"
+       @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
+       @test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
+       @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
+       @test "$(sse)" = "yes" || test "$(sse)" = "no"
+       @test "$(pext)" = "yes" || test "$(pext)" = "no"
+       @test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang"
+
+$(EXE): $(OBJS)
+       $(CXX) -o $@ $(OBJS) $(LDFLAGS)
+
+gcc-profile-prepare:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean
+
+gcc-profile-make:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+       EXTRACXXFLAGS='-fprofile-generate' \
+       EXTRALDFLAGS='-lgcov' \
+       all
+
+gcc-profile-use:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+       EXTRACXXFLAGS='-fprofile-use' \
+       EXTRALDFLAGS='-lgcov' \
+       all
+
+gcc-profile-clean:
+       @rm -rf *.gcda *.gcno bench.txt
+
+icc-profile-prepare:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
+       @mkdir profdir
+
+icc-profile-make:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+       EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
+       all
+
+icc-profile-use:
+       $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+       EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
+       all
+
+icc-profile-clean:
+       @rm -rf profdir bench.txt
+
+.depend:
+       -@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
+
+-include .depend
+
+
+### ==========================================================================
+### Section 6. Non-standard targets
+### ==========================================================================
+
+hpux:
+       $(MAKE) \
+       CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -mt +O3 -DNDEBUG -DNO_PREFETCH' \
+       CXXFLAGS="" \
+       LDFLAGS="" \
+       all
+
diff --git a/src/benchmark.cpp b/src/benchmark.cpp
new file mode 100644 (file)
index 0000000..f82ec62
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <fstream>
+#include <iostream>
+#include <istream>
+#include <vector>
+
+#include "misc.h"
+#include "notation.h"
+#include "position.h"
+#include "search.h"
+#include "thread.h"
+#include "tt.h"
+#include "ucioption.h"
+
+using namespace std;
+
+static const char* Defaults[] = {
+  "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
+  "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
+  "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11",
+  "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
+  "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
+  "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
+  "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15",
+  "r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13",
+  "r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16",
+  "4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17",
+  "2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11",
+  "r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
+  "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
+  "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
+  "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
+  "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26",
+  "6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1",
+  "3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1",
+  "2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1",
+  "8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1",
+  "7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1",
+  "8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1",
+  "8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1",
+  "8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1",
+  "8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1",
+  "5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1",
+  "6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1",
+  "1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1",
+  "6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1",
+  "8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1"
+};
+
+
+/// benchmark() runs a simple benchmark by letting Stockfish analyze a set
+/// of positions for a given limit each. There are five parameters: the
+/// transposition table size, the number of search threads that should
+/// be used, the limit value spent for each position (optional, default is
+/// depth 13), an optional file name where to look for positions in FEN
+/// format (defaults are the positions defined above) and the type of the
+/// limit value: depth (default), time in secs or number of nodes.
+
+void benchmark(const Position& current, istream& is) {
+
+  string token;
+  Search::LimitsType limits;
+  vector<string> fens;
+
+  // Assign default values to missing arguments
+  string ttSize    = (is >> token) ? token : "16";
+  string threads   = (is >> token) ? token : "1";
+  string limit     = (is >> token) ? token : "13";
+  string fenFile   = (is >> token) ? token : "default";
+  string limitType = (is >> token) ? token : "depth";
+
+  Options["Hash"]    = ttSize;
+  Options["Threads"] = threads;
+  TT.clear();
+
+  if (limitType == "time")
+      limits.movetime = 1000 * atoi(limit.c_str()); // movetime is in ms
+
+  else if (limitType == "nodes")
+      limits.nodes = atoi(limit.c_str());
+
+  else if (limitType == "mate")
+      limits.mate = atoi(limit.c_str());
+
+  else
+      limits.depth = atoi(limit.c_str());
+
+  if (fenFile == "default")
+      fens.assign(Defaults, Defaults + 30);
+
+  else if (fenFile == "current")
+      fens.push_back(current.fen());
+
+  else
+  {
+      string fen;
+      ifstream file(fenFile.c_str());
+
+      if (!file.is_open())
+      {
+          cerr << "Unable to open file " << fenFile << endl;
+          return;
+      }
+
+      while (getline(file, fen))
+          if (!fen.empty())
+              fens.push_back(fen);
+
+      file.close();
+  }
+
+  uint64_t nodes = 0;
+  Search::StateStackPtr st;
+  Time::point elapsed = Time::now();
+
+  for (size_t i = 0; i < fens.size(); ++i)
+  {
+      Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
+
+      cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
+
+      if (limitType == "perft")
+          nodes += Search::perft<true>(pos, limits.depth * ONE_PLY);
+
+      else
+      {
+          Threads.start_thinking(pos, limits, st);
+          Threads.wait_for_think_finished();
+          nodes += Search::RootPos.nodes_searched();
+      }
+  }
+
+  elapsed = Time::now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
+
+  dbg_print(); // Just before to exit
+
+  cerr << "\n==========================="
+       << "\nTotal time (ms) : " << elapsed
+       << "\nNodes searched  : " << nodes
+       << "\nNodes/second    : " << 1000 * nodes / elapsed << endl;
+}
diff --git a/src/bitbase.cpp b/src/bitbase.cpp
new file mode 100644 (file)
index 0000000..0f274c8
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cassert>
+#include <vector>
+
+#include "bitboard.h"
+#include "types.h"
+
+namespace {
+
+  // There are 24 possible pawn squares: the first 4 files and ranks from 2 to 7
+  const unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608
+
+  // Each uint32_t stores results of 32 positions, one per bit
+  uint32_t KPKBitbase[MAX_INDEX / 32];
+
+  // A KPK bitbase index is an integer in [0, IndexMax] range
+  //
+  // Information is mapped in a way that minimizes the number of iterations:
+  //
+  // bit  0- 5: white king square (from SQ_A1 to SQ_H8)
+  // bit  6-11: black king square (from SQ_A1 to SQ_H8)
+  // bit    12: side to move (WHITE or BLACK)
+  // bit 13-14: white pawn file (from FILE_A to FILE_D)
+  // bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
+  unsigned index(Color us, Square bksq, Square wksq, Square psq) {
+    return wksq + (bksq << 6) + (us << 12) + (file_of(psq) << 13) + ((RANK_7 - rank_of(psq)) << 15);
+  }
+
+  enum Result {
+    INVALID = 0,
+    UNKNOWN = 1,
+    DRAW    = 2,
+    WIN     = 4
+  };
+
+  inline Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
+
+  struct KPKPosition {
+
+    KPKPosition(unsigned idx);
+    operator Result() const { return result; }
+    Result classify(const std::vector<KPKPosition>& db)
+    { return us == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
+
+  private:
+    template<Color Us> Result classify(const std::vector<KPKPosition>& db);
+
+    Color us;
+    Square bksq, wksq, psq;
+    Result result;
+  };
+
+} // namespace
+
+
+bool Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color us) {
+
+  assert(file_of(wpsq) <= FILE_D);
+
+  unsigned idx = index(us, bksq, wksq, wpsq);
+  return KPKBitbase[idx / 32] & (1 << (idx & 0x1F));
+}
+
+
+void Bitbases::init_kpk() {
+
+  unsigned idx, repeat = 1;
+  std::vector<KPKPosition> db;
+  db.reserve(MAX_INDEX);
+
+  // Initialize db with known win / draw positions
+  for (idx = 0; idx < MAX_INDEX; ++idx)
+      db.push_back(KPKPosition(idx));
+
+  // Iterate through the positions until none of the unknown positions can be
+  // changed to either wins or draws (15 cycles needed).
+  while (repeat)
+      for (repeat = idx = 0; idx < MAX_INDEX; ++idx)
+          repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN);
+
+  // Map 32 results into one KPKBitbase[] entry
+  for (idx = 0; idx < MAX_INDEX; ++idx)
+      if (db[idx] == WIN)
+          KPKBitbase[idx / 32] |= 1 << (idx & 0x1F);
+}
+
+
+namespace {
+
+  KPKPosition::KPKPosition(unsigned idx) {
+
+    wksq   = Square((idx >>  0) & 0x3F);
+    bksq   = Square((idx >>  6) & 0x3F);
+    us     = Color ((idx >> 12) & 0x01);
+    psq    = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
+    result = UNKNOWN;
+
+    // Check if two pieces are on the same square or if a king can be captured
+    if (   square_distance(wksq, bksq) <= 1
+        || wksq == psq
+        || bksq == psq
+        || (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq)))
+        result = INVALID;
+
+    else if (us == WHITE)
+    {
+        // Immediate win if a pawn can be promoted without getting captured
+        if (   rank_of(psq) == RANK_7
+            && wksq != psq + DELTA_N
+            && (   square_distance(bksq, psq + DELTA_N) > 1
+                ||(StepAttacksBB[KING][wksq] & (psq + DELTA_N))))
+            result = WIN;
+    }
+    // Immediate draw if it is a stalemate or a king captures undefended pawn
+    else if (  !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq]))
+             || (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq]))
+        result = DRAW;
+  }
+
+  template<Color Us>
+  Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
+
+    // White to Move: If one move leads to a position classified as WIN, the result
+    // of the current position is WIN. If all moves lead to positions classified
+    // as DRAW, the current position is classified as DRAW, otherwise the current
+    // position is classified as UNKNOWN.
+    //
+    // Black to Move: If one move leads to a position classified as DRAW, the result
+    // of the current position is DRAW. If all moves lead to positions classified
+    // as WIN, the position is classified as WIN, otherwise the current position is
+    // classified as UNKNOWN.
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    Result r = INVALID;
+    Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq];
+
+    while (b)
+        r |= Us == WHITE ? db[index(Them, bksq, pop_lsb(&b), psq)]
+                         : db[index(Them, pop_lsb(&b), wksq, psq)];
+
+    if (Us == WHITE && rank_of(psq) < RANK_7)
+    {
+        Square s = psq + DELTA_N;
+        r |= db[index(BLACK, bksq, wksq, s)]; // Single push
+
+        if (rank_of(psq) == RANK_2 && s != wksq && s != bksq)
+            r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push
+    }
+
+    if (Us == WHITE)
+        return result = r & WIN  ? WIN  : r & UNKNOWN ? UNKNOWN : DRAW;
+    else
+        return result = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN;
+  }
+
+} // namespace
diff --git a/src/bitboard.cpp b/src/bitboard.cpp
new file mode 100644 (file)
index 0000000..b3dbd00
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cstring> // For memset
+
+#include "bitboard.h"
+#include "bitcount.h"
+#include "rkiss.h"
+
+CACHE_LINE_ALIGNMENT
+
+Bitboard RMasks[SQUARE_NB];
+Bitboard RMagics[SQUARE_NB];
+Bitboard* RAttacks[SQUARE_NB];
+unsigned RShifts[SQUARE_NB];
+
+Bitboard BMasks[SQUARE_NB];
+Bitboard BMagics[SQUARE_NB];
+Bitboard* BAttacks[SQUARE_NB];
+unsigned BShifts[SQUARE_NB];
+
+Bitboard SquareBB[SQUARE_NB];
+Bitboard FileBB[FILE_NB];
+Bitboard RankBB[RANK_NB];
+Bitboard AdjacentFilesBB[FILE_NB];
+Bitboard InFrontBB[COLOR_NB][RANK_NB];
+Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
+Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
+Bitboard LineBB[SQUARE_NB][SQUARE_NB];
+Bitboard DistanceRingsBB[SQUARE_NB][8];
+Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
+Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
+Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
+Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
+
+int SquareDistance[SQUARE_NB][SQUARE_NB];
+
+namespace {
+
+  // De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan
+  const uint64_t DeBruijn_64 = 0x3F79D71B4CB0A89ULL;
+  const uint32_t DeBruijn_32 = 0x783A9B23;
+
+  CACHE_LINE_ALIGNMENT
+
+  int MS1BTable[256];
+  Square BSFTable[SQUARE_NB];
+  Bitboard RTable[0x19000]; // Storage space for rook attacks
+  Bitboard BTable[0x1480];  // Storage space for bishop attacks
+
+  typedef unsigned (Fn)(Square, Bitboard);
+
+  void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
+                   Bitboard masks[], unsigned shifts[], Square deltas[], Fn index);
+
+  FORCE_INLINE unsigned bsf_index(Bitboard b) {
+
+    // Matt Taylor's folding for 32 bit systems, extended to 64 bits by Kim Walisch
+    b ^= (b - 1);
+    return Is64Bit ? (b * DeBruijn_64) >> 58
+                   : ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn_32) >> 26;
+  }
+}
+
+/// lsb()/msb() finds the least/most significant bit in a non-zero bitboard.
+/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard.
+
+#ifndef USE_BSFQ
+
+Square lsb(Bitboard b) { return BSFTable[bsf_index(b)]; }
+
+Square pop_lsb(Bitboard* b) {
+
+  Bitboard bb = *b;
+  *b = bb & (bb - 1);
+  return BSFTable[bsf_index(bb)];
+}
+
+Square msb(Bitboard b) {
+
+  unsigned b32;
+  int result = 0;
+
+  if (b > 0xFFFFFFFF)
+  {
+      b >>= 32;
+      result = 32;
+  }
+
+  b32 = unsigned(b);
+
+  if (b32 > 0xFFFF)
+  {
+      b32 >>= 16;
+      result += 16;
+  }
+
+  if (b32 > 0xFF)
+  {
+      b32 >>= 8;
+      result += 8;
+  }
+
+  return Square(result + MS1BTable[b32]);
+}
+
+#endif // ifndef USE_BSFQ
+
+
+/// Bitboards::pretty() returns an ASCII representation of a bitboard to be
+/// printed to standard output. This is sometimes useful for debugging.
+
+const std::string Bitboards::pretty(Bitboard b) {
+
+  std::string s = "+---+---+---+---+---+---+---+---+\n";
+
+  for (Rank r = RANK_8; r >= RANK_1; --r)
+  {
+      for (File f = FILE_A; f <= FILE_H; ++f)
+          s.append(b & make_square(f, r) ? "| X " : "|   ");
+
+      s.append("|\n+---+---+---+---+---+---+---+---+\n");
+  }
+
+  return s;
+}
+
+
+/// Bitboards::init() initializes various bitboard tables. It is called at
+/// startup and relies on global objects to be already zero-initialized.
+
+void Bitboards::init() {
+
+  for (Square s = SQ_A1; s <= SQ_H8; ++s)
+  {
+      SquareBB[s] = 1ULL << s;
+      BSFTable[bsf_index(SquareBB[s])] = s;
+  }
+
+  for (Bitboard b = 1; b < 256; ++b)
+      MS1BTable[b] = more_than_one(b) ? MS1BTable[b - 1] : lsb(b);
+
+  for (File f = FILE_A; f <= FILE_H; ++f)
+      FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB;
+
+  for (Rank r = RANK_1; r <= RANK_8; ++r)
+      RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB;
+
+  for (File f = FILE_A; f <= FILE_H; ++f)
+      AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0);
+
+  for (Rank r = RANK_1; r < RANK_8; ++r)
+      InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[BLACK][r] | RankBB[r]);
+
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (Square s = SQ_A1; s <= SQ_H8; ++s)
+      {
+          ForwardBB[c][s]      = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)];
+          PawnAttackSpan[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)];
+          PassedPawnMask[c][s] = ForwardBB[c][s] | PawnAttackSpan[c][s];
+      }
+
+  for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
+      for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
+          if (s1 != s2)
+          {
+              SquareDistance[s1][s2] = std::max(file_distance(s1, s2), rank_distance(s1, s2));
+              DistanceRingsBB[s1][SquareDistance[s1][s2] - 1] |= s2;
+          }
+
+  int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 },
+                     {}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } };
+
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (PieceType pt = PAWN; pt <= KING; ++pt)
+          for (Square s = SQ_A1; s <= SQ_H8; ++s)
+              for (int i = 0; steps[pt][i]; ++i)
+              {
+                  Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]);
+
+                  if (is_ok(to) && square_distance(s, to) < 3)
+                      StepAttacksBB[make_piece(c, pt)][s] |= to;
+              }
+
+  Square RDeltas[] = { DELTA_N,  DELTA_E,  DELTA_S,  DELTA_W  };
+  Square BDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW };
+
+  init_magics(RTable, RAttacks, RMagics, RMasks, RShifts, RDeltas, magic_index<ROOK>);
+  init_magics(BTable, BAttacks, BMagics, BMasks, BShifts, BDeltas, magic_index<BISHOP>);
+
+  for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
+  {
+      PseudoAttacks[QUEEN][s1]  = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
+      PseudoAttacks[QUEEN][s1] |= PseudoAttacks[  ROOK][s1] = attacks_bb<  ROOK>(s1, 0);
+
+      for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
+      {
+          Piece pc = (PseudoAttacks[BISHOP][s1] & s2) ? W_BISHOP :
+                     (PseudoAttacks[ROOK][s1]   & s2) ? W_ROOK   : NO_PIECE;
+
+          if (pc == NO_PIECE)
+              continue;
+
+          LineBB[s1][s2] = (attacks_bb(pc, s1, 0) & attacks_bb(pc, s2, 0)) | s1 | s2;
+          BetweenBB[s1][s2] = attacks_bb(pc, s1, SquareBB[s2]) & attacks_bb(pc, s2, SquareBB[s1]);
+      }
+  }
+}
+
+
+namespace {
+
+  Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) {
+
+    Bitboard attack = 0;
+
+    for (int i = 0; i < 4; ++i)
+        for (Square s = sq + deltas[i];
+             is_ok(s) && square_distance(s, s - deltas[i]) == 1;
+             s += deltas[i])
+        {
+            attack |= s;
+
+            if (occupied & s)
+                break;
+        }
+
+    return attack;
+  }
+
+
+  // init_magics() computes all rook and bishop attacks at startup. Magic
+  // bitboards are used to look up attacks of sliding pieces. As a reference see
+  // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
+  // use the so called "fancy" approach.
+
+  void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
+                   Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) {
+
+    int MagicBoosters[][RANK_NB] = { {  969, 1976, 2850,  542, 2069, 2852, 1708,  164 },
+                                     { 3101,  552, 3555,  926,  834,   26, 2131, 1117 } };
+    RKISS rk;
+    Bitboard occupancy[4096], reference[4096], edges, b;
+    int i, size, booster;
+
+    // attacks[s] is a pointer to the beginning of the attacks table for square 's'
+    attacks[SQ_A1] = table;
+
+    for (Square s = SQ_A1; s <= SQ_H8; ++s)
+    {
+        // Board edges are not considered in the relevant occupancies
+        edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
+
+        // Given a square 's', the mask is the bitboard of sliding attacks from
+        // 's' computed on an empty board. The index must be big enough to contain
+        // all the attacks for each possible subset of the mask and so is 2 power
+        // the number of 1s of the mask. Hence we deduce the size of the shift to
+        // apply to the 64 or 32 bits word to get the index.
+        masks[s]  = sliding_attack(deltas, s, 0) & ~edges;
+        shifts[s] = (Is64Bit ? 64 : 32) - popcount<Max15>(masks[s]);
+
+        // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
+        // store the corresponding sliding attack bitboard in reference[].
+        b = size = 0;
+        do {
+            occupancy[size] = b;
+            reference[size] = sliding_attack(deltas, s, b);
+
+            if (HasPext)
+                attacks[s][_pext_u64(b, masks[s])] = reference[size];
+
+            size++;
+            b = (b - masks[s]) & masks[s];
+        } while (b);
+
+        // Set the offset for the table of the next square. We have individual
+        // table sizes for each square with "Fancy Magic Bitboards".
+        if (s < SQ_H8)
+            attacks[s + 1] = attacks[s] + size;
+
+        if (HasPext)
+            continue;
+
+        booster = MagicBoosters[Is64Bit][rank_of(s)];
+
+        // Find a magic for square 's' picking up an (almost) random number
+        // until we find the one that passes the verification test.
+        do {
+            do
+                magics[s] = rk.magic_rand<Bitboard>(booster);
+            while (popcount<Max15>((magics[s] * masks[s]) >> 56) < 6);
+
+            std::memset(attacks[s], 0, size * sizeof(Bitboard));
+
+            // A good magic must map every possible occupancy to an index that
+            // looks up the correct sliding attack in the attacks[s] database.
+            // Note that we build up the database for square 's' as a side
+            // effect of verifying the magic.
+            for (i = 0; i < size; ++i)
+            {
+                Bitboard& attack = attacks[s][index(s, occupancy[i])];
+
+                if (attack && attack != reference[i])
+                    break;
+
+                assert(reference[i]);
+
+                attack = reference[i];
+            }
+        } while (i < size);
+    }
+  }
+}
diff --git a/src/bitboard.h b/src/bitboard.h
new file mode 100644 (file)
index 0000000..6a1755b
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BITBOARD_H_INCLUDED
+#define BITBOARD_H_INCLUDED
+
+#include <string>
+
+#include "types.h"
+
+namespace Bitboards {
+
+void init();
+const std::string pretty(Bitboard b);
+
+}
+
+namespace Bitbases {
+
+void init_kpk();
+bool probe_kpk(Square wksq, Square wpsq, Square bksq, Color us);
+
+}
+
+const Bitboard FileABB = 0x0101010101010101ULL;
+const Bitboard FileBBB = FileABB << 1;
+const Bitboard FileCBB = FileABB << 2;
+const Bitboard FileDBB = FileABB << 3;
+const Bitboard FileEBB = FileABB << 4;
+const Bitboard FileFBB = FileABB << 5;
+const Bitboard FileGBB = FileABB << 6;
+const Bitboard FileHBB = FileABB << 7;
+
+const Bitboard Rank1BB = 0xFF;
+const Bitboard Rank2BB = Rank1BB << (8 * 1);
+const Bitboard Rank3BB = Rank1BB << (8 * 2);
+const Bitboard Rank4BB = Rank1BB << (8 * 3);
+const Bitboard Rank5BB = Rank1BB << (8 * 4);
+const Bitboard Rank6BB = Rank1BB << (8 * 5);
+const Bitboard Rank7BB = Rank1BB << (8 * 6);
+const Bitboard Rank8BB = Rank1BB << (8 * 7);
+
+CACHE_LINE_ALIGNMENT
+
+extern Bitboard RMasks[SQUARE_NB];
+extern Bitboard RMagics[SQUARE_NB];
+extern Bitboard* RAttacks[SQUARE_NB];
+extern unsigned RShifts[SQUARE_NB];
+
+extern Bitboard BMasks[SQUARE_NB];
+extern Bitboard BMagics[SQUARE_NB];
+extern Bitboard* BAttacks[SQUARE_NB];
+extern unsigned BShifts[SQUARE_NB];
+
+extern Bitboard SquareBB[SQUARE_NB];
+extern Bitboard FileBB[FILE_NB];
+extern Bitboard RankBB[RANK_NB];
+extern Bitboard AdjacentFilesBB[FILE_NB];
+extern Bitboard InFrontBB[COLOR_NB][RANK_NB];
+extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
+extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
+extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
+extern Bitboard DistanceRingsBB[SQUARE_NB][8];
+extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
+extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
+extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
+extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
+
+extern int SquareDistance[SQUARE_NB][SQUARE_NB];
+
+const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
+
+/// Overloads of bitwise operators between a Bitboard and a Square for testing
+/// whether a given bit is set in a bitboard, and for setting and clearing bits.
+
+inline Bitboard operator&(Bitboard b, Square s) {
+  return b & SquareBB[s];
+}
+
+inline Bitboard& operator|=(Bitboard& b, Square s) {
+  return b |= SquareBB[s];
+}
+
+inline Bitboard& operator^=(Bitboard& b, Square s) {
+  return b ^= SquareBB[s];
+}
+
+inline Bitboard operator|(Bitboard b, Square s) {
+  return b | SquareBB[s];
+}
+
+inline Bitboard operator^(Bitboard b, Square s) {
+  return b ^ SquareBB[s];
+}
+
+inline bool more_than_one(Bitboard b) {
+  return b & (b - 1);
+}
+
+inline int square_distance(Square s1, Square s2) {
+  return SquareDistance[s1][s2];
+}
+
+inline int file_distance(Square s1, Square s2) {
+  return abs(file_of(s1) - file_of(s2));
+}
+
+inline int rank_distance(Square s1, Square s2) {
+  return abs(rank_of(s1) - rank_of(s2));
+}
+
+
+/// shift_bb() moves bitboard one step along direction Delta. Mainly for pawns.
+
+template<Square Delta>
+inline Bitboard shift_bb(Bitboard b) {
+
+  return  Delta == DELTA_N  ?  b             << 8 : Delta == DELTA_S  ?  b             >> 8
+        : Delta == DELTA_NE ? (b & ~FileHBB) << 9 : Delta == DELTA_SE ? (b & ~FileHBB) >> 7
+        : Delta == DELTA_NW ? (b & ~FileABB) << 7 : Delta == DELTA_SW ? (b & ~FileABB) >> 9
+        : 0;
+}
+
+
+/// rank_bb() and file_bb() take a file or a square as input and return
+/// a bitboard representing all squares on the given file or rank.
+
+inline Bitboard rank_bb(Rank r) {
+  return RankBB[r];
+}
+
+inline Bitboard rank_bb(Square s) {
+  return RankBB[rank_of(s)];
+}
+
+inline Bitboard file_bb(File f) {
+  return FileBB[f];
+}
+
+inline Bitboard file_bb(Square s) {
+  return FileBB[file_of(s)];
+}
+
+
+/// adjacent_files_bb() takes a file as input and returns a bitboard representing
+/// all squares on the adjacent files.
+
+inline Bitboard adjacent_files_bb(File f) {
+  return AdjacentFilesBB[f];
+}
+
+
+/// in_front_bb() takes a color and a rank as input, and returns a bitboard
+/// representing all the squares on all ranks in front of the rank, from the
+/// given color's point of view. For instance, in_front_bb(BLACK, RANK_3) will
+/// give all squares on ranks 1 and 2.
+
+inline Bitboard in_front_bb(Color c, Rank r) {
+  return InFrontBB[c][r];
+}
+
+
+/// between_bb() returns a bitboard representing all squares between two squares.
+/// For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with the bits for
+/// square d5 and e6 set.  If s1 and s2 are not on the same rank, file or diagonal,
+/// 0 is returned.
+
+inline Bitboard between_bb(Square s1, Square s2) {
+  return BetweenBB[s1][s2];
+}
+
+
+/// forward_bb() takes a color and a square as input, and returns a bitboard
+/// representing all squares along the line in front of the square, from the
+/// point of view of the given color. Definition of the table is:
+/// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s)
+
+inline Bitboard forward_bb(Color c, Square s) {
+  return ForwardBB[c][s];
+}
+
+
+/// pawn_attack_span() takes a color and a square as input, and returns a bitboard
+/// representing all squares that can be attacked by a pawn of the given color
+/// when it moves along its file starting from the given square. Definition is:
+/// PawnAttackSpan[c][s] = in_front_bb(c, s) & adjacent_files_bb(s);
+
+inline Bitboard pawn_attack_span(Color c, Square s) {
+  return PawnAttackSpan[c][s];
+}
+
+
+/// passed_pawn_mask() takes a color and a square as input, and returns a
+/// bitboard mask which can be used to test if a pawn of the given color on
+/// the given square is a passed pawn. Definition of the table is:
+/// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_bb(c, s)
+
+inline Bitboard passed_pawn_mask(Color c, Square s) {
+  return PassedPawnMask[c][s];
+}
+
+
+/// squares_of_color() returns a bitboard representing all squares with the same
+/// color of the given square.
+
+inline Bitboard squares_of_color(Square s) {
+  return DarkSquares & s ? DarkSquares : ~DarkSquares;
+}
+
+
+/// aligned() returns true if the squares s1, s2 and s3 are aligned
+/// either on a straight or on a diagonal line.
+
+inline bool aligned(Square s1, Square s2, Square s3) {
+  return LineBB[s1][s2] & s3;
+}
+
+
+/// Functions for computing sliding attack bitboards. Function attacks_bb() takes
+/// a square and a bitboard of occupied squares as input, and returns a bitboard
+/// representing all squares attacked by Pt (bishop or rook) on the given square.
+template<PieceType Pt>
+FORCE_INLINE unsigned magic_index(Square s, Bitboard occ) {
+
+  Bitboard* const Masks  = Pt == ROOK ? RMasks  : BMasks;
+  Bitboard* const Magics = Pt == ROOK ? RMagics : BMagics;
+  unsigned* const Shifts = Pt == ROOK ? RShifts : BShifts;
+
+  if (HasPext)
+      return unsigned(_pext_u64(occ, Masks[s]));
+
+  if (Is64Bit)
+      return unsigned(((occ & Masks[s]) * Magics[s]) >> Shifts[s]);
+
+  unsigned lo = unsigned(occ) & unsigned(Masks[s]);
+  unsigned hi = unsigned(occ >> 32) & unsigned(Masks[s] >> 32);
+  return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s];
+}
+
+template<PieceType Pt>
+inline Bitboard attacks_bb(Square s, Bitboard occ) {
+  return (Pt == ROOK ? RAttacks : BAttacks)[s][magic_index<Pt>(s, occ)];
+}
+
+inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occ) {
+
+  switch (type_of(pc))
+  {
+  case BISHOP: return attacks_bb<BISHOP>(s, occ);
+  case ROOK  : return attacks_bb<ROOK>(s, occ);
+  case QUEEN : return attacks_bb<BISHOP>(s, occ) | attacks_bb<ROOK>(s, occ);
+  default    : return StepAttacksBB[pc][s];
+  }
+}
+
+/// lsb()/msb() finds the least/most significant bit in a non-zero bitboard.
+/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard.
+
+#ifdef USE_BSFQ
+
+#  if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+
+FORCE_INLINE Square lsb(Bitboard b) {
+  unsigned long idx;
+  _BitScanForward64(&idx, b);
+  return (Square) idx;
+}
+
+FORCE_INLINE Square msb(Bitboard b) {
+  unsigned long idx;
+  _BitScanReverse64(&idx, b);
+  return (Square) idx;
+}
+
+#  elif defined(__arm__)
+
+FORCE_INLINE int lsb32(uint32_t v) {
+  __asm__("rbit %0, %1" : "=r"(v) : "r"(v));
+  return __builtin_clz(v);
+}
+
+FORCE_INLINE Square msb(Bitboard b) {
+  return (Square) (63 - __builtin_clzll(b));
+}
+
+FORCE_INLINE Square lsb(Bitboard b) {
+  return (Square) (uint32_t(b) ? lsb32(uint32_t(b)) : 32 + lsb32(uint32_t(b >> 32)));
+}
+
+#  else
+
+FORCE_INLINE Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen
+  Bitboard idx;
+  __asm__("bsfq %1, %0": "=r"(idx): "rm"(b) );
+  return (Square) idx;
+}
+
+FORCE_INLINE Square msb(Bitboard b) {
+  Bitboard idx;
+  __asm__("bsrq %1, %0": "=r"(idx): "rm"(b) );
+  return (Square) idx;
+}
+
+#  endif
+
+FORCE_INLINE Square pop_lsb(Bitboard* b) {
+  const Square s = lsb(*b);
+  *b &= *b - 1;
+  return s;
+}
+
+#else // if defined(USE_BSFQ)
+
+extern Square msb(Bitboard b);
+extern Square lsb(Bitboard b);
+extern Square pop_lsb(Bitboard* b);
+
+#endif
+
+/// frontmost_sq() and backmost_sq() find the square corresponding to the
+/// most/least advanced bit relative to the given color.
+
+inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); }
+inline Square  backmost_sq(Color c, Bitboard b) { return c == WHITE ? lsb(b) : msb(b); }
+
+#endif // #ifndef BITBOARD_H_INCLUDED
diff --git a/src/bitcount.h b/src/bitcount.h
new file mode 100644 (file)
index 0000000..f84c51c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BITCOUNT_H_INCLUDED
+#define BITCOUNT_H_INCLUDED
+
+#include <cassert>
+#include "types.h"
+
+enum BitCountType {
+  CNT_64,
+  CNT_64_MAX15,
+  CNT_32,
+  CNT_32_MAX15,
+  CNT_HW_POPCNT
+};
+
+/// Determine at compile time the best popcount<> specialization according to
+/// whether the platform is 32 or 64 bit, the maximum number of non-zero
+/// bits to count and if the hardware popcnt instruction is available.
+const BitCountType Full  = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32;
+const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15;
+
+
+/// popcount() counts the number of non-zero bits in a bitboard
+template<BitCountType> inline int popcount(Bitboard);
+
+template<>
+inline int popcount<CNT_64>(Bitboard b) {
+  b -=  (b >> 1) & 0x5555555555555555ULL;
+  b  = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
+  b  = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL;
+  return (b * 0x0101010101010101ULL) >> 56;
+}
+
+template<>
+inline int popcount<CNT_64_MAX15>(Bitboard b) {
+  b -=  (b >> 1) & 0x5555555555555555ULL;
+  b  = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
+  return (b * 0x1111111111111111ULL) >> 60;
+}
+
+template<>
+inline int popcount<CNT_32>(Bitboard b) {
+  unsigned w = unsigned(b >> 32), v = unsigned(b);
+  v -=  (v >> 1) & 0x55555555; // 0-2 in 2 bits
+  w -=  (w >> 1) & 0x55555555;
+  v  = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
+  w  = ((w >> 2) & 0x33333333) + (w & 0x33333333);
+  v  = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F;
+  return (v * 0x01010101) >> 24;
+}
+
+template<>
+inline int popcount<CNT_32_MAX15>(Bitboard b) {
+  unsigned w = unsigned(b >> 32), v = unsigned(b);
+  v -=  (v >> 1) & 0x55555555; // 0-2 in 2 bits
+  w -=  (w >> 1) & 0x55555555;
+  v  = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
+  w  = ((w >> 2) & 0x33333333) + (w & 0x33333333);
+  return ((v + w) * 0x11111111) >> 28;
+}
+
+template<>
+inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
+
+#ifndef USE_POPCNT
+
+  assert(false);
+  return b != 0; // Avoid 'b not used' warning
+
+#elif defined(_MSC_VER) && defined(__INTEL_COMPILER)
+
+  return _mm_popcnt_u64(b);
+
+#elif defined(_MSC_VER)
+
+  return (int)__popcnt64(b);
+
+#else
+
+  __asm__("popcnt %1, %0" : "=r" (b) : "r" (b));
+  return b;
+
+#endif
+}
+
+#endif // #ifndef BITCOUNT_H_INCLUDED
diff --git a/src/endgame.cpp b/src/endgame.cpp
new file mode 100644 (file)
index 0000000..311443e
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cassert>
+
+#include "bitboard.h"
+#include "bitcount.h"
+#include "endgame.h"
+#include "movegen.h"
+
+using std::string;
+
+namespace {
+
+  // Table used to drive the king towards the edge of the board
+  // in KX vs K and KQ vs KR endgames.
+  const int PushToEdges[SQUARE_NB] = {
+    100, 90, 80, 70, 70, 80, 90, 100,
+     90, 70, 60, 50, 50, 60, 70,  90,
+     80, 60, 40, 30, 30, 40, 60,  80,
+     70, 50, 30, 20, 20, 30, 50,  70,
+     70, 50, 30, 20, 20, 30, 50,  70,
+     80, 60, 40, 30, 30, 40, 60,  80,
+     90, 70, 60, 50, 50, 60, 70,  90,
+    100, 90, 80, 70, 70, 80, 90, 100,
+  };
+
+  // Table used to drive the king towards a corner square of the
+  // right color in KBN vs K endgames.
+  const int PushToCorners[SQUARE_NB] = {
+    200, 190, 180, 170, 160, 150, 140, 130,
+    190, 180, 170, 160, 150, 140, 130, 140,
+    180, 170, 155, 140, 140, 125, 140, 150,
+    170, 160, 140, 120, 110, 140, 150, 160,
+    160, 150, 140, 110, 120, 140, 160, 170,
+    150, 140, 125, 140, 140, 155, 170, 180,
+    140, 130, 140, 150, 160, 170, 180, 190,
+    130, 140, 150, 160, 170, 180, 190, 200
+  };
+
+  // Tables used to drive a piece towards or away from another piece
+  const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
+  const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
+
+#ifndef NDEBUG
+  bool verify_material(const Position& pos, Color c, Value npm, int num_pawns) {
+    return pos.non_pawn_material(c) == npm && pos.count<PAWN>(c) == num_pawns;
+  }
+#endif
+
+  // Map the square as if strongSide is white and strongSide's only pawn
+  // is on the left half of the board.
+  Square normalize(const Position& pos, Color strongSide, Square sq) {
+
+    assert(pos.count<PAWN>(strongSide) == 1);
+
+    if (file_of(pos.list<PAWN>(strongSide)[0]) >= FILE_E)
+        sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1
+
+    if (strongSide == BLACK)
+        sq = ~sq;
+
+    return sq;
+  }
+
+  // Get the material key of Position out of the given endgame key code
+  // like "KBPKN". The trick here is to first forge an ad-hoc FEN string
+  // and then let a Position object do the work for us.
+  Key key(const string& code, Color c) {
+
+    assert(code.length() > 0 && code.length() < 8);
+    assert(code[0] == 'K');
+
+    string sides[] = { code.substr(code.find('K', 1)),      // Weak
+                       code.substr(0, code.find('K', 1)) }; // Strong
+
+    std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
+
+    string fen =  sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+                + sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
+
+    return Position(fen, false, NULL).material_key();
+  }
+
+  template<typename M>
+  void delete_endgame(const typename M::value_type& p) { delete p.second; }
+
+} // namespace
+
+
+/// Endgames members definitions
+
+Endgames::Endgames() {
+
+  add<KPK>("KPK");
+  add<KNNK>("KNNK");
+  add<KBNK>("KBNK");
+  add<KRKP>("KRKP");
+  add<KRKB>("KRKB");
+  add<KRKN>("KRKN");
+  add<KQKP>("KQKP");
+  add<KQKR>("KQKR");
+
+  add<KNPK>("KNPK");
+  add<KNPKB>("KNPKB");
+  add<KRPKR>("KRPKR");
+  add<KRPKB>("KRPKB");
+  add<KBPKB>("KBPKB");
+  add<KBPKN>("KBPKN");
+  add<KBPPKB>("KBPPKB");
+  add<KRPPKRP>("KRPPKRP");
+}
+
+Endgames::~Endgames() {
+
+  for_each(m1.begin(), m1.end(), delete_endgame<M1>);
+  for_each(m2.begin(), m2.end(), delete_endgame<M2>);
+}
+
+template<EndgameType E>
+void Endgames::add(const string& code) {
+
+  map((Endgame<E>*)0)[key(code, WHITE)] = new Endgame<E>(WHITE);
+  map((Endgame<E>*)0)[key(code, BLACK)] = new Endgame<E>(BLACK);
+}
+
+
+/// Mate with KX vs K. This function is used to evaluate positions with
+/// king and plenty of material vs a lone king. It simply gives the
+/// attacking side a bonus for driving the defending king towards the edge
+/// of the board, and for keeping the distance between the two kings small.
+template<>
+Value Endgame<KXK>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+  assert(!pos.checkers()); // Eval is never called when in check
+
+  // Stalemate detection with lone king
+  if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
+      return VALUE_DRAW;
+
+  Square winnerKSq = pos.king_square(strongSide);
+  Square loserKSq = pos.king_square(weakSide);
+
+  Value result =  pos.non_pawn_material(strongSide)
+                + pos.count<PAWN>(strongSide) * PawnValueEg
+                + PushToEdges[loserKSq]
+                + PushClose[square_distance(winnerKSq, loserKSq)];
+
+  if (   pos.count<QUEEN>(strongSide)
+      || pos.count<ROOK>(strongSide)
+      ||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
+      || pos.bishop_pair(strongSide))
+      result += VALUE_KNOWN_WIN;
+
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
+/// defending king towards a corner square of the right color.
+template<>
+Value Endgame<KBNK>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+  Square winnerKSq = pos.king_square(strongSide);
+  Square loserKSq = pos.king_square(weakSide);
+  Square bishopSq = pos.list<BISHOP>(strongSide)[0];
+
+  // kbnk_mate_table() tries to drive toward corners A1 or H8. If we have a
+  // bishop that cannot reach the above squares, we flip the kings in order
+  // to drive the enemy toward corners A8 or H1.
+  if (opposite_colors(bishopSq, SQ_A1))
+  {
+      winnerKSq = ~winnerKSq;
+      loserKSq  = ~loserKSq;
+  }
+
+  Value result =  VALUE_KNOWN_WIN
+                + PushClose[square_distance(winnerKSq, loserKSq)]
+                + PushToCorners[loserKSq];
+
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KP vs K. This endgame is evaluated with the help of a bitbase.
+template<>
+Value Endgame<KPK>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+  // Assume strongSide is white and the pawn is on files A-D
+  Square wksq = normalize(pos, strongSide, pos.king_square(strongSide));
+  Square bksq = normalize(pos, strongSide, pos.king_square(weakSide));
+  Square psq  = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
+
+  Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
+
+  if (!Bitbases::probe_kpk(wksq, psq, bksq, us))
+      return VALUE_DRAW;
+
+  Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq));
+
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
+/// a bitbase. The function below returns drawish scores when the pawn is
+/// far advanced with support of the king, while the attacking king is far
+/// away.
+template<>
+Value Endgame<KRKP>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, RookValueMg, 0));
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
+
+  Square wksq = relative_square(strongSide, pos.king_square(strongSide));
+  Square bksq = relative_square(strongSide, pos.king_square(weakSide));
+  Square rsq  = relative_square(strongSide, pos.list<ROOK>(strongSide)[0]);
+  Square psq  = relative_square(strongSide, pos.list<PAWN>(weakSide)[0]);
+
+  Square queeningSq = make_square(file_of(psq), RANK_1);
+  Value result;
+
+  // If the stronger side's king is in front of the pawn, it's a win
+  if (wksq < psq && file_of(wksq) == file_of(psq))
+      result = RookValueEg - square_distance(wksq, psq);
+
+  // If the weaker side's king is too far from the pawn and the rook,
+  // it's a win.
+  else if (   square_distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide)
+           && square_distance(bksq, rsq) >= 3)
+      result = RookValueEg - square_distance(wksq, psq);
+
+  // If the pawn is far advanced and supported by the defending king,
+  // the position is drawish
+  else if (   rank_of(bksq) <= RANK_3
+           && square_distance(bksq, psq) == 1
+           && rank_of(wksq) >= RANK_4
+           && square_distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide))
+      result = Value(80) - 8 * square_distance(wksq, psq);
+
+  else
+      result =  Value(200) - 8 * (  square_distance(wksq, psq + DELTA_S)
+                                  - square_distance(bksq, psq + DELTA_S)
+                                  - square_distance(psq, queeningSq));
+
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KR vs KB. This is very simple, and always returns drawish scores.  The
+/// score is slightly bigger when the defending king is close to the edge.
+template<>
+Value Endgame<KRKB>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, RookValueMg, 0));
+  assert(verify_material(pos, weakSide, BishopValueMg, 0));
+
+  Value result = Value(PushToEdges[pos.king_square(weakSide)]);
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KR vs KN. The attacking side has slightly better winning chances than
+/// in KR vs KB, particularly if the king and the knight are far apart.
+template<>
+Value Endgame<KRKN>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, RookValueMg, 0));
+  assert(verify_material(pos, weakSide, KnightValueMg, 0));
+
+  Square bksq = pos.king_square(weakSide);
+  Square bnsq = pos.list<KNIGHT>(weakSide)[0];
+  Value result = Value(PushToEdges[bksq] + PushAway[square_distance(bksq, bnsq)]);
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KQ vs KP. In general, this is a win for the stronger side, but there are a
+/// few important exceptions. A pawn on 7th rank and on the A,C,F or H files
+/// with a king positioned next to it can be a draw, so in that case, we only
+/// use the distance between the kings.
+template<>
+Value Endgame<KQKP>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, QueenValueMg, 0));
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
+
+  Square winnerKSq = pos.king_square(strongSide);
+  Square loserKSq = pos.king_square(weakSide);
+  Square pawnSq = pos.list<PAWN>(weakSide)[0];
+
+  Value result = Value(PushClose[square_distance(winnerKSq, loserKSq)]);
+
+  if (   relative_rank(weakSide, pawnSq) != RANK_7
+      || square_distance(loserKSq, pawnSq) != 1
+      || !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq))
+      result += QueenValueEg - PawnValueEg;
+
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KQ vs KR.  This is almost identical to KX vs K:  We give the attacking
+/// king a bonus for having the kings close together, and for forcing the
+/// defending king towards the edge. If we also take care to avoid null move for
+/// the defending side in the search, this is usually sufficient to win KQ vs KR.
+template<>
+Value Endgame<KQKR>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, QueenValueMg, 0));
+  assert(verify_material(pos, weakSide, RookValueMg, 0));
+
+  Square winnerKSq = pos.king_square(strongSide);
+  Square loserKSq = pos.king_square(weakSide);
+
+  Value result =  QueenValueEg
+                - RookValueEg
+                + PushToEdges[loserKSq]
+                + PushClose[square_distance(winnerKSq, loserKSq)];
+
+  return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// Some cases of trivial draws
+template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
+
+
+/// KB and one or more pawns vs K. It checks for draws with rook pawns and
+/// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
+/// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
+/// will be used.
+template<>
+ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
+
+  assert(pos.non_pawn_material(strongSide) == BishopValueMg);
+  assert(pos.count<PAWN>(strongSide) >= 1);
+
+  // No assertions about the material of weakSide, because we want draws to
+  // be detected even when the weaker side has some pawns.
+
+  Bitboard pawns = pos.pieces(strongSide, PAWN);
+  File pawnFile = file_of(pos.list<PAWN>(strongSide)[0]);
+
+  // All pawns are on a single rook file ?
+  if (    (pawnFile == FILE_A || pawnFile == FILE_H)
+      && !(pawns & ~file_bb(pawnFile)))
+  {
+      Square bishopSq = pos.list<BISHOP>(strongSide)[0];
+      Square queeningSq = relative_square(strongSide, make_square(pawnFile, RANK_8));
+      Square kingSq = pos.king_square(weakSide);
+
+      if (   opposite_colors(queeningSq, bishopSq)
+          && square_distance(queeningSq, kingSq) <= 1)
+          return SCALE_FACTOR_DRAW;
+  }
+
+  // If all the pawns are on the same B or G file, then it's potentially a draw
+  if (    (pawnFile == FILE_B || pawnFile == FILE_G)
+      && !(pos.pieces(PAWN) & ~file_bb(pawnFile))
+      && pos.non_pawn_material(weakSide) == 0
+      && pos.count<PAWN>(weakSide) >= 1)
+  {
+      // Get weakSide pawn that is closest to the home rank
+      Square weakPawnSq = backmost_sq(weakSide, pos.pieces(weakSide, PAWN));
+
+      Square strongKingSq = pos.king_square(strongSide);
+      Square weakKingSq = pos.king_square(weakSide);
+      Square bishopSq = pos.list<BISHOP>(strongSide)[0];
+
+      // There's potential for a draw if our pawn is blocked on the 7th rank,
+      // the bishop cannot attack it or they only have one pawn left
+      if (   relative_rank(strongSide, weakPawnSq) == RANK_7
+          && (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide)))
+          && (opposite_colors(bishopSq, weakPawnSq) || pos.count<PAWN>(strongSide) == 1))
+      {
+          int strongKingDist = square_distance(weakPawnSq, strongKingSq);
+          int weakKingDist = square_distance(weakPawnSq, weakKingSq);
+
+          // It's a draw if the weak king is on its back two ranks, within 2
+          // squares of the blocking pawn and the strong king is not
+          // closer. (I think this rule only fails in practically
+          // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
+          // and positions where qsearch will immediately correct the
+          // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
+          if (   relative_rank(strongSide, weakKingSq) >= RANK_7
+              && weakKingDist <= 2
+              && weakKingDist <= strongKingDist)
+              return SCALE_FACTOR_DRAW;
+      }
+  }
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KQ vs KR and one or more pawns. It tests for fortress draws with a rook on
+/// the third rank defended by a pawn.
+template<>
+ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, QueenValueMg, 0));
+  assert(pos.count<ROOK>(weakSide) == 1);
+  assert(pos.count<PAWN>(weakSide) >= 1);
+
+  Square kingSq = pos.king_square(weakSide);
+  Square rsq = pos.list<ROOK>(weakSide)[0];
+
+  if (    relative_rank(weakSide, kingSq) <= RANK_2
+      &&  relative_rank(weakSide, pos.king_square(strongSide)) >= RANK_4
+      &&  relative_rank(weakSide, rsq) == RANK_3
+      && (  pos.pieces(weakSide, PAWN)
+          & pos.attacks_from<KING>(kingSq)
+          & pos.attacks_from<PAWN>(rsq, strongSide)))
+          return SCALE_FACTOR_DRAW;
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KRP vs KR. This function knows a handful of the most important classes of
+/// drawn positions, but is far from perfect. It would probably be a good idea
+/// to add more knowledge in the future.
+///
+/// It would also be nice to rewrite the actual code for this function,
+/// which is mostly copied from Glaurung 1.x, and isn't very pretty.
+template<>
+ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, RookValueMg, 1));
+  assert(verify_material(pos, weakSide,   RookValueMg, 0));
+
+  // Assume strongSide is white and the pawn is on files A-D
+  Square wksq = normalize(pos, strongSide, pos.king_square(strongSide));
+  Square bksq = normalize(pos, strongSide, pos.king_square(weakSide));
+  Square wrsq = normalize(pos, strongSide, pos.list<ROOK>(strongSide)[0]);
+  Square wpsq = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
+  Square brsq = normalize(pos, strongSide, pos.list<ROOK>(weakSide)[0]);
+
+  File f = file_of(wpsq);
+  Rank r = rank_of(wpsq);
+  Square queeningSq = make_square(f, RANK_8);
+  int tempo = (pos.side_to_move() == strongSide);
+
+  // If the pawn is not too far advanced and the defending king defends the
+  // queening square, use the third-rank defence.
+  if (   r <= RANK_5
+      && square_distance(bksq, queeningSq) <= 1
+      && wksq <= SQ_H5
+      && (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6)))
+      return SCALE_FACTOR_DRAW;
+
+  // The defending side saves a draw by checking from behind in case the pawn
+  // has advanced to the 6th rank with the king behind.
+  if (   r == RANK_6
+      && square_distance(bksq, queeningSq) <= 1
+      && rank_of(wksq) + tempo <= RANK_6
+      && (rank_of(brsq) == RANK_1 || (!tempo && abs(file_of(brsq) - f) >= 3)))
+      return SCALE_FACTOR_DRAW;
+
+  if (   r >= RANK_6
+      && bksq == queeningSq
+      && rank_of(brsq) == RANK_1
+      && (!tempo || square_distance(wksq, wpsq) >= 2))
+      return SCALE_FACTOR_DRAW;
+
+  // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
+  // and the black rook is behind the pawn.
+  if (   wpsq == SQ_A7
+      && wrsq == SQ_A8
+      && (bksq == SQ_H7 || bksq == SQ_G7)
+      && file_of(brsq) == FILE_A
+      && (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5))
+      return SCALE_FACTOR_DRAW;
+
+  // If the defending king blocks the pawn and the attacking king is too far
+  // away, it's a draw.
+  if (   r <= RANK_5
+      && bksq == wpsq + DELTA_N
+      && square_distance(wksq, wpsq) - tempo >= 2
+      && square_distance(wksq, brsq) - tempo >= 2)
+      return SCALE_FACTOR_DRAW;
+
+  // Pawn on the 7th rank supported by the rook from behind usually wins if the
+  // attacking king is closer to the queening square than the defending king,
+  // and the defending king cannot gain tempi by threatening the attacking rook.
+  if (   r == RANK_7
+      && f != FILE_A
+      && file_of(wrsq) == f
+      && wrsq != queeningSq
+      && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo)
+      && (square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo))
+      return ScaleFactor(SCALE_FACTOR_MAX - 2 * square_distance(wksq, queeningSq));
+
+  // Similar to the above, but with the pawn further back
+  if (   f != FILE_A
+      && file_of(wrsq) == f
+      && wrsq < wpsq
+      && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo)
+      && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wpsq + DELTA_N) - 2 + tempo)
+      && (  square_distance(bksq, wrsq) + tempo >= 3
+          || (    square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo
+              && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo))))
+      return ScaleFactor(  SCALE_FACTOR_MAX
+                         - 8 * square_distance(wpsq, queeningSq)
+                         - 2 * square_distance(wksq, queeningSq));
+
+  // If the pawn is not far advanced and the defending king is somewhere in
+  // the pawn's path, it's probably a draw.
+  if (r <= RANK_4 && bksq > wpsq)
+  {
+      if (file_of(bksq) == file_of(wpsq))
+          return ScaleFactor(10);
+      if (   abs(file_of(bksq) - file_of(wpsq)) == 1
+          && square_distance(wksq, bksq) > 2)
+          return ScaleFactor(24 - 2 * square_distance(wksq, bksq));
+  }
+  return SCALE_FACTOR_NONE;
+}
+
+template<>
+ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, RookValueMg, 1));
+  assert(verify_material(pos, weakSide, BishopValueMg, 0));
+
+  // Test for a rook pawn
+  if (pos.pieces(PAWN) & (FileABB | FileHBB))
+  {
+      Square ksq = pos.king_square(weakSide);
+      Square bsq = pos.list<BISHOP>(weakSide)[0];
+      Square psq = pos.list<PAWN>(strongSide)[0];
+      Rank rk = relative_rank(strongSide, psq);
+      Square push = pawn_push(strongSide);
+
+      // If the pawn is on the 5th rank and the pawn (currently) is on
+      // the same color square as the bishop then there is a chance of
+      // a fortress. Depending on the king position give a moderate
+      // reduction or a stronger one if the defending king is near the
+      // corner but not trapped there.
+      if (rk == RANK_5 && !opposite_colors(bsq, psq))
+      {
+          int d = square_distance(psq + 3 * push, ksq);
+
+          if (d <= 2 && !(d == 0 && ksq == pos.king_square(strongSide) + 2 * push))
+              return ScaleFactor(24);
+          else
+              return ScaleFactor(48);
+      }
+
+      // When the pawn has moved to the 6th rank we can be fairly sure
+      // it's drawn if the bishop attacks the square in front of the
+      // pawn from a reasonable distance and the defending king is near
+      // the corner
+      if (   rk == RANK_6
+          && square_distance(psq + 2 * push, ksq) <= 1
+          && (PseudoAttacks[BISHOP][bsq] & (psq + push))
+          && file_distance(bsq, psq) >= 2)
+          return ScaleFactor(8);
+  }
+
+  return SCALE_FACTOR_NONE;
+}
+
+/// KRPP vs KRP. There is just a single rule: if the stronger side has no passed
+/// pawns and the defending king is actively placed, the position is drawish.
+template<>
+ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, RookValueMg, 2));
+  assert(verify_material(pos, weakSide,   RookValueMg, 1));
+
+  Square wpsq1 = pos.list<PAWN>(strongSide)[0];
+  Square wpsq2 = pos.list<PAWN>(strongSide)[1];
+  Square bksq = pos.king_square(weakSide);
+
+  // Does the stronger side have a passed pawn?
+  if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2))
+      return SCALE_FACTOR_NONE;
+
+  Rank r = std::max(relative_rank(strongSide, wpsq1), relative_rank(strongSide, wpsq2));
+
+  if (   file_distance(bksq, wpsq1) <= 1
+      && file_distance(bksq, wpsq2) <= 1
+      && relative_rank(strongSide, bksq) > r)
+  {
+      switch (r) {
+      case RANK_2: return ScaleFactor(10);
+      case RANK_3: return ScaleFactor(10);
+      case RANK_4: return ScaleFactor(15);
+      case RANK_5: return ScaleFactor(20);
+      case RANK_6: return ScaleFactor(40);
+      default: assert(false);
+      }
+  }
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// K and two or more pawns vs K. There is just a single rule here: If all pawns
+/// are on the same rook file and are blocked by the defending king, it's a draw.
+template<>
+ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
+
+  assert(pos.non_pawn_material(strongSide) == VALUE_ZERO);
+  assert(pos.count<PAWN>(strongSide) >= 2);
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+  Square ksq = pos.king_square(weakSide);
+  Bitboard pawns = pos.pieces(strongSide, PAWN);
+  Square psq = pos.list<PAWN>(strongSide)[0];
+
+  // If all pawns are ahead of the king, on a single rook file and
+  // the king is within one file of the pawns, it's a draw.
+  if (   !(pawns & ~in_front_bb(weakSide, rank_of(ksq)))
+      && !((pawns & ~FileABB) && (pawns & ~FileHBB))
+      && file_distance(ksq, psq) <= 1)
+      return SCALE_FACTOR_DRAW;
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KBP vs KB. There are two rules: if the defending king is somewhere along the
+/// path of the pawn, and the square of the king is not of the same color as the
+/// stronger side's bishop, it's a draw. If the two bishops have opposite color,
+/// it's almost always a draw.
+template<>
+ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, BishopValueMg, 1));
+  assert(verify_material(pos, weakSide,   BishopValueMg, 0));
+
+  Square pawnSq = pos.list<PAWN>(strongSide)[0];
+  Square strongBishopSq = pos.list<BISHOP>(strongSide)[0];
+  Square weakBishopSq = pos.list<BISHOP>(weakSide)[0];
+  Square weakKingSq = pos.king_square(weakSide);
+
+  // Case 1: Defending king blocks the pawn, and cannot be driven away
+  if (   file_of(weakKingSq) == file_of(pawnSq)
+      && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
+      && (   opposite_colors(weakKingSq, strongBishopSq)
+          || relative_rank(strongSide, weakKingSq) <= RANK_6))
+      return SCALE_FACTOR_DRAW;
+
+  // Case 2: Opposite colored bishops
+  if (opposite_colors(strongBishopSq, weakBishopSq))
+  {
+      // We assume that the position is drawn in the following three situations:
+      //
+      //   a. The pawn is on rank 5 or further back.
+      //   b. The defending king is somewhere in the pawn's path.
+      //   c. The defending bishop attacks some square along the pawn's path,
+      //      and is at least three squares away from the pawn.
+      //
+      // These rules are probably not perfect, but in practice they work
+      // reasonably well.
+
+      if (relative_rank(strongSide, pawnSq) <= RANK_5)
+          return SCALE_FACTOR_DRAW;
+      else
+      {
+          Bitboard path = forward_bb(strongSide, pawnSq);
+
+          if (path & pos.pieces(weakSide, KING))
+              return SCALE_FACTOR_DRAW;
+
+          if (  (pos.attacks_from<BISHOP>(weakBishopSq) & path)
+              && square_distance(weakBishopSq, pawnSq) >= 3)
+              return SCALE_FACTOR_DRAW;
+      }
+  }
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KBPP vs KB. It detects a few basic draws with opposite-colored bishops
+template<>
+ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, BishopValueMg, 2));
+  assert(verify_material(pos, weakSide,   BishopValueMg, 0));
+
+  Square wbsq = pos.list<BISHOP>(strongSide)[0];
+  Square bbsq = pos.list<BISHOP>(weakSide)[0];
+
+  if (!opposite_colors(wbsq, bbsq))
+      return SCALE_FACTOR_NONE;
+
+  Square ksq = pos.king_square(weakSide);
+  Square psq1 = pos.list<PAWN>(strongSide)[0];
+  Square psq2 = pos.list<PAWN>(strongSide)[1];
+  Rank r1 = rank_of(psq1);
+  Rank r2 = rank_of(psq2);
+  Square blockSq1, blockSq2;
+
+  if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2))
+  {
+      blockSq1 = psq1 + pawn_push(strongSide);
+      blockSq2 = make_square(file_of(psq2), rank_of(psq1));
+  }
+  else
+  {
+      blockSq1 = psq2 + pawn_push(strongSide);
+      blockSq2 = make_square(file_of(psq1), rank_of(psq2));
+  }
+
+  switch (file_distance(psq1, psq2))
+  {
+  case 0:
+    // Both pawns are on the same file. It's an easy draw if the defender firmly
+    // controls some square in the frontmost pawn's path.
+    if (   file_of(ksq) == file_of(blockSq1)
+        && relative_rank(strongSide, ksq) >= relative_rank(strongSide, blockSq1)
+        && opposite_colors(ksq, wbsq))
+        return SCALE_FACTOR_DRAW;
+    else
+        return SCALE_FACTOR_NONE;
+
+  case 1:
+    // Pawns on adjacent files. It's a draw if the defender firmly controls the
+    // square in front of the frontmost pawn's path, and the square diagonally
+    // behind this square on the file of the other pawn.
+    if (   ksq == blockSq1
+        && opposite_colors(ksq, wbsq)
+        && (   bbsq == blockSq2
+            || (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(weakSide, BISHOP))
+            || abs(r1 - r2) >= 2))
+        return SCALE_FACTOR_DRAW;
+
+    else if (   ksq == blockSq2
+             && opposite_colors(ksq, wbsq)
+             && (   bbsq == blockSq1
+                 || (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(weakSide, BISHOP))))
+        return SCALE_FACTOR_DRAW;
+    else
+        return SCALE_FACTOR_NONE;
+
+  default:
+    // The pawns are not on the same file or adjacent files. No scaling.
+    return SCALE_FACTOR_NONE;
+  }
+}
+
+
+/// KBP vs KN. There is a single rule: If the defending king is somewhere along
+/// the path of the pawn, and the square of the king is not of the same color as
+/// the stronger side's bishop, it's a draw.
+template<>
+ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, BishopValueMg, 1));
+  assert(verify_material(pos, weakSide, KnightValueMg, 0));
+
+  Square pawnSq = pos.list<PAWN>(strongSide)[0];
+  Square strongBishopSq = pos.list<BISHOP>(strongSide)[0];
+  Square weakKingSq = pos.king_square(weakSide);
+
+  if (   file_of(weakKingSq) == file_of(pawnSq)
+      && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
+      && (   opposite_colors(weakKingSq, strongBishopSq)
+          || relative_rank(strongSide, weakKingSq) <= RANK_6))
+      return SCALE_FACTOR_DRAW;
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KNP vs K. There is a single rule: if the pawn is a rook pawn on the 7th rank
+/// and the defending king prevents the pawn from advancing, the position is drawn.
+template<>
+ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, KnightValueMg, 1));
+  assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+  // Assume strongSide is white and the pawn is on files A-D
+  Square pawnSq     = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
+  Square weakKingSq = normalize(pos, strongSide, pos.king_square(weakSide));
+
+  if (pawnSq == SQ_A7 && square_distance(SQ_A8, weakKingSq) <= 1)
+      return SCALE_FACTOR_DRAW;
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KNP vs KB. If knight can block bishop from taking pawn, it's a win.
+/// Otherwise the position is drawn.
+template<>
+ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
+
+  Square pawnSq = pos.list<PAWN>(strongSide)[0];
+  Square bishopSq = pos.list<BISHOP>(weakSide)[0];
+  Square weakKingSq = pos.king_square(weakSide);
+
+  // King needs to get close to promoting pawn to prevent knight from blocking.
+  // Rules for this are very tricky, so just approximate.
+  if (forward_bb(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
+      return ScaleFactor(square_distance(weakKingSq, pawnSq));
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KP vs KP. This is done by removing the weakest side's pawn and probing the
+/// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably
+/// has at least a draw with the pawn as well. The exception is when the stronger
+/// side's pawn is far advanced and not on a rook file; in this case it is often
+/// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
+template<>
+ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
+
+  assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
+  assert(verify_material(pos, weakSide,   VALUE_ZERO, 1));
+
+  // Assume strongSide is white and the pawn is on files A-D
+  Square wksq = normalize(pos, strongSide, pos.king_square(strongSide));
+  Square bksq = normalize(pos, strongSide, pos.king_square(weakSide));
+  Square psq  = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
+
+  Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
+
+  // If the pawn has advanced to the fifth rank or further, and is not a
+  // rook pawn, it's too dangerous to assume that it's at least a draw.
+  if (rank_of(psq) >= RANK_5 && file_of(psq) != FILE_A)
+      return SCALE_FACTOR_NONE;
+
+  // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
+  // it's probably at least a draw even with the pawn.
+  return Bitbases::probe_kpk(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
+}
diff --git a/src/endgame.h b/src/endgame.h
new file mode 100644 (file)
index 0000000..c3d5dd0
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef ENDGAME_H_INCLUDED
+#define ENDGAME_H_INCLUDED
+
+#include <map>
+#include <string>
+
+#include "position.h"
+#include "types.h"
+
+
+/// EndgameType lists all supported endgames
+
+enum EndgameType {
+
+  // Evaluation functions
+
+  KNNK,  // KNN vs K
+  KXK,   // Generic "mate lone king" eval
+  KBNK,  // KBN vs K
+  KPK,   // KP vs K
+  KRKP,  // KR vs KP
+  KRKB,  // KR vs KB
+  KRKN,  // KR vs KN
+  KQKP,  // KQ vs KP
+  KQKR,  // KQ vs KR
+
+
+  // Scaling functions
+  SCALE_FUNS,
+
+  KBPsK,   // KB and pawns vs K
+  KQKRPs,  // KQ vs KR and pawns
+  KRPKR,   // KRP vs KR
+  KRPKB,   // KRP vs KB
+  KRPPKRP, // KRPP vs KRP
+  KPsK,    // K and pawns vs K
+  KBPKB,   // KBP vs KB
+  KBPPKB,  // KBPP vs KB
+  KBPKN,   // KBP vs KN
+  KNPK,    // KNP vs K
+  KNPKB,   // KNP vs KB
+  KPKP     // KP vs KP
+};
+
+
+/// Endgame functions can be of two types depending on whether they return a
+/// Value or a ScaleFactor. Type eg_fun<int>::type returns either ScaleFactor
+/// or Value depending on whether the template parameter is 0 or 1.
+
+template<int> struct eg_fun { typedef Value type; };
+template<> struct eg_fun<1> { typedef ScaleFactor type; };
+
+
+/// Base and derived templates for endgame evaluation and scaling functions
+
+template<typename T>
+struct EndgameBase {
+
+  virtual ~EndgameBase() {}
+  virtual Color color() const = 0;
+  virtual T operator()(const Position&) const = 0;
+};
+
+
+template<EndgameType E, typename T = typename eg_fun<(E > SCALE_FUNS)>::type>
+struct Endgame : public EndgameBase<T> {
+
+  explicit Endgame(Color c) : strongSide(c), weakSide(~c) {}
+  Color color() const { return strongSide; }
+  T operator()(const Position&) const;
+
+private:
+  const Color strongSide, weakSide;
+};
+
+
+/// The Endgames class stores the pointers to endgame evaluation and scaling
+/// base objects in two std::map typedefs. We then use polymorphism to invoke
+/// the actual endgame function by calling its virtual operator().
+
+class Endgames {
+
+  typedef std::map<Key, EndgameBase<eg_fun<0>::type>*> M1;
+  typedef std::map<Key, EndgameBase<eg_fun<1>::type>*> M2;
+
+  M1 m1;
+  M2 m2;
+
+  M1& map(M1::mapped_type) { return m1; }
+  M2& map(M2::mapped_type) { return m2; }
+
+  template<EndgameType E> void add(const std::string& code);
+
+public:
+  Endgames();
+ ~Endgames();
+
+  template<typename T> T probe(Key key, T& eg)
+  { return eg = map(eg).count(key) ? map(eg)[key] : NULL; }
+};
+
+#endif // #ifndef ENDGAME_H_INCLUDED
diff --git a/src/evaluate.cpp b/src/evaluate.cpp
new file mode 100644 (file)
index 0000000..9f62706
--- /dev/null
@@ -0,0 +1,880 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+#include <sstream>
+
+#include "bitcount.h"
+#include "evaluate.h"
+#include "material.h"
+#include "pawns.h"
+#include "thread.h"
+#include "ucioption.h"
+
+namespace {
+
+  // Struct EvalInfo contains various information computed and collected
+  // by the evaluation functions.
+  struct EvalInfo {
+
+    // Pointers to material and pawn hash table entries
+    Material::Entry* mi;
+    Pawns::Entry* pi;
+
+    // attackedBy[color][piece type] is a bitboard representing all squares
+    // attacked by a given color and piece type, attackedBy[color][ALL_PIECES]
+    // contains all squares attacked by the given color.
+    Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
+
+    // kingRing[color] is the zone around the king which is considered
+    // by the king safety evaluation. This consists of the squares directly
+    // adjacent to the king, and the three (or two, for a king on an edge file)
+    // squares two ranks in front of the king. For instance, if black's king
+    // is on g8, kingRing[BLACK] is a bitboard containing the squares f8, h8,
+    // f7, g7, h7, f6, g6 and h6.
+    Bitboard kingRing[COLOR_NB];
+
+    // kingAttackersCount[color] is the number of pieces of the given color
+    // which attack a square in the kingRing of the enemy king.
+    int kingAttackersCount[COLOR_NB];
+
+    // kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
+    // given color which attack a square in the kingRing of the enemy king. The
+    // weights of the individual piece types are given by the variables
+    // QueenAttackWeight, RookAttackWeight, BishopAttackWeight and
+    // KnightAttackWeight in evaluate.cpp
+    int kingAttackersWeight[COLOR_NB];
+
+    // kingAdjacentZoneAttacksCount[color] is the number of attacks to squares
+    // directly adjacent to the king of the given color. Pieces which attack
+    // more than one square are counted multiple times. For instance, if black's
+    // king is on g8 and there's a white knight on g5, this knight adds
+    // 2 to kingAdjacentZoneAttacksCount[BLACK].
+    int kingAdjacentZoneAttacksCount[COLOR_NB];
+
+    Bitboard pinnedPieces[COLOR_NB];
+  };
+
+  namespace Tracing {
+
+    enum Terms { // First 8 entries are for PieceType
+      MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERMS_NB
+    };
+
+    Score terms[COLOR_NB][TERMS_NB];
+    EvalInfo ei;
+    ScaleFactor sf;
+
+    double to_cp(Value v);
+    void add_term(int idx, Score term_w, Score term_b = SCORE_ZERO);
+    void format_row(std::stringstream& ss, const char* name, int idx);
+    std::string do_trace(const Position& pos);
+  }
+
+  // Evaluation weights, indexed by evaluation term
+  enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety };
+  const struct Weight { int mg, eg; } Weights[] = {
+    {289, 344}, {233, 201}, {221, 273}, {46, 0}, {318, 0}
+  };
+
+  typedef Value V;
+  #define S(mg, eg) make_score(mg, eg)
+
+  // MobilityBonus[PieceType][attacked] contains bonuses for middle and end
+  // game, indexed by piece type and number of attacked squares not occupied by
+  // friendly pieces.
+  const Score MobilityBonus[][32] = {
+    {}, {},
+    { S(-65,-50), S(-42,-30), S(-9,-10), S( 3,  0), S(15, 10), S(27, 20), // Knights
+      S( 37, 28), S( 42, 31), S(44, 33) },
+    { S(-52,-47), S(-28,-23), S( 6,  1), S(20, 15), S(34, 29), S(48, 43), // Bishops
+      S( 60, 55), S( 68, 63), S(74, 68), S(77, 72), S(80, 75), S(82, 77),
+      S( 84, 79), S( 86, 81) },
+    { S(-47,-53), S(-31,-26), S(-5,  0), S( 1, 16), S( 7, 32), S(13, 48), // Rooks
+      S( 18, 64), S( 22, 80), S(26, 96), S(29,109), S(31,115), S(33,119),
+      S( 35,122), S( 36,123), S(37,124) },
+    { S(-42,-40), S(-28,-23), S(-5, -7), S( 0,  0), S( 6, 10), S(11, 19), // Queens
+      S( 13, 29), S( 18, 38), S(20, 40), S(21, 41), S(22, 41), S(22, 41),
+      S( 22, 41), S( 23, 41), S(24, 41), S(25, 41), S(25, 41), S(25, 41),
+      S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
+      S( 25, 41), S( 25, 41), S(25, 41), S(25, 41) }
+  };
+
+  // Outpost[PieceType][Square] contains bonuses for knights and bishops outposts,
+  // indexed by piece type and square (from white's point of view).
+  const Value Outpost[][SQUARE_NB] = {
+  {// A     B     C     D     E     F     G     H
+    V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Knights
+    V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0),
+    V(0), V(0), V(4), V(8), V(8), V(4), V(0), V(0),
+    V(0), V(4),V(17),V(26),V(26),V(17), V(4), V(0),
+    V(0), V(8),V(26),V(35),V(35),V(26), V(8), V(0),
+    V(0), V(4),V(17),V(17),V(17),V(17), V(4), V(0) },
+  {
+    V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Bishops
+    V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0),
+    V(0), V(0), V(5), V(5), V(5), V(5), V(0), V(0),
+    V(0), V(5),V(10),V(10),V(10),V(10), V(5), V(0),
+    V(0),V(10),V(21),V(21),V(21),V(21),V(10), V(0),
+    V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0) }
+  };
+
+  // Threat[attacking][attacked] contains bonuses according to which piece
+  // type attacks which one.
+  const Score Threat[][PIECE_TYPE_NB] = {
+    { S(0, 0), S( 7, 39), S(24, 49), S(24, 49), S(41,100), S(41,100) }, // Minor
+    { S(0, 0), S(15, 39), S(15, 45), S(15, 45), S(15, 45), S(24, 49) }  // Major
+  };
+
+  // ThreatenedByPawn[PieceType] contains a penalty according to which piece
+  // type is attacked by an enemy pawn.
+  const Score ThreatenedByPawn[] = {
+    S(0, 0), S(0, 0), S(80, 119), S(80, 119), S(117, 199), S(127, 218)
+  };
+
+  // Hanging contains a bonus for each enemy hanging piece
+  const Score Hanging = S(23, 20);
+
+  #undef S
+
+  const Score RookOnPawn       = make_score(10, 28);
+  const Score RookOpenFile     = make_score(43, 21);
+  const Score RookSemiopenFile = make_score(19, 10);
+  const Score BishopPawns      = make_score( 8, 12);
+  const Score MinorBehindPawn  = make_score(16,  0);
+  const Score TrappedRook      = make_score(92,  0);
+  const Score Unstoppable      = make_score( 0, 20);
+
+  // Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
+  // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
+  // happen in Chess960 games.
+  const Score TrappedBishopA1H1 = make_score(50, 50);
+
+  // SpaceMask[Color] contains the area of the board which is considered
+  // by the space evaluation. In the middlegame, each side is given a bonus
+  // based on how many squares inside this area are safe and available for
+  // friendly minor pieces.
+  const Bitboard SpaceMask[] = {
+    (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank2BB | Rank3BB | Rank4BB),
+    (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank7BB | Rank6BB | Rank5BB)
+  };
+
+  // King danger constants and variables. The king danger scores are taken
+  // from KingDanger[]. Various little "meta-bonuses" measuring the strength
+  // of the enemy attack are added up into an integer, which is used as an
+  // index to KingDanger[].
+  //
+  // KingAttackWeights[PieceType] contains king attack weights by piece type
+  const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 };
+
+  // Bonuses for enemy's safe checks
+  const int QueenContactCheck = 24;
+  const int RookContactCheck  = 16;
+  const int QueenCheck        = 12;
+  const int RookCheck         = 8;
+  const int BishopCheck       = 2;
+  const int KnightCheck       = 3;
+
+  // KingDanger[attackUnits] contains the actual king danger weighted
+  // scores, indexed by a calculated integer number.
+  Score KingDanger[128];
+
+
+  // apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow
+  Score apply_weight(Score v, const Weight& w) {
+    return make_score(mg_value(v) * w.mg / 256, eg_value(v) * w.eg / 256);
+  }
+
+
+  // init_eval_info() initializes king bitboards for given color adding
+  // pawn attacks. To be done at the beginning of the evaluation.
+
+  template<Color Us>
+  void init_eval_info(const Position& pos, EvalInfo& ei) {
+
+    const Color  Them = (Us == WHITE ? BLACK : WHITE);
+    const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
+
+    ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
+
+    Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.king_square(Them));
+    ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
+
+    // Init king safety tables only if we are going to use them
+    if (pos.count<QUEEN>(Us) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
+    {
+        ei.kingRing[Them] = b | shift_bb<Down>(b);
+        b &= ei.attackedBy[Us][PAWN];
+        ei.kingAttackersCount[Us] = b ? popcount<Max15>(b) : 0;
+        ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
+    }
+    else
+        ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0;
+  }
+
+
+  // evaluate_outpost() evaluates bishop and knight outpost squares
+
+  template<PieceType Pt, Color Us>
+  Score evaluate_outpost(const Position& pos, const EvalInfo& ei, Square s) {
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    assert (Pt == BISHOP || Pt == KNIGHT);
+
+    // Initial bonus based on square
+    Value bonus = Outpost[Pt == BISHOP][relative_square(Us, s)];
+
+    // Increase bonus if supported by pawn, especially if the opponent has
+    // no minor piece which can trade with the outpost piece.
+    if (bonus && (ei.attackedBy[Us][PAWN] & s))
+    {
+        if (   !pos.pieces(Them, KNIGHT)
+            && !(squares_of_color(s) & pos.pieces(Them, BISHOP)))
+            bonus += bonus + bonus / 2;
+        else
+            bonus += bonus / 2;
+    }
+
+    return make_score(bonus * 2, bonus / 2);
+  }
+
+
+  // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color
+
+  template<PieceType Pt, Color Us, bool Trace>
+  Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea) {
+
+    Bitboard b;
+    Square s;
+    Score score = SCORE_ZERO;
+
+    const PieceType NextPt = (Us == WHITE ? Pt : PieceType(Pt + 1));
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+    const Square* pl = pos.list<Pt>(Us);
+
+    ei.attackedBy[Us][Pt] = 0;
+
+    while ((s = *pl++) != SQ_NONE)
+    {
+        // Find attacked squares, including x-ray attacks for bishops and rooks
+        b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN))
+          : Pt ==   ROOK ? attacks_bb<  ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
+                         : pos.attacks_from<Pt>(s);
+
+        if (ei.pinnedPieces[Us] & s)
+            b &= LineBB[pos.king_square(Us)][s];
+
+        ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b;
+
+        if (b & ei.kingRing[Them])
+        {
+            ei.kingAttackersCount[Us]++;
+            ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
+            Bitboard bb = b & ei.attackedBy[Them][KING];
+            if (bb)
+                ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
+        }
+
+        if (Pt == QUEEN)
+            b &= ~(  ei.attackedBy[Them][KNIGHT]
+                   | ei.attackedBy[Them][BISHOP]
+                   | ei.attackedBy[Them][ROOK]);
+
+        int mob = Pt != QUEEN ? popcount<Max15>(b & mobilityArea[Us])
+                              : popcount<Full >(b & mobilityArea[Us]);
+
+        mobility[Us] += MobilityBonus[Pt][mob];
+
+        // Decrease score if we are attacked by an enemy pawn. The remaining part
+        // of threat evaluation must be done later when we have full attack info.
+        if (ei.attackedBy[Them][PAWN] & s)
+            score -= ThreatenedByPawn[Pt];
+
+        if (Pt == BISHOP || Pt == KNIGHT)
+        {
+            // Penalty for bishop with same colored pawns
+            if (Pt == BISHOP)
+                score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
+
+            // Bishop and knight outpost square
+            if (!(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s)))
+                score += evaluate_outpost<Pt, Us>(pos, ei, s);
+
+            // Bishop or knight behind a pawn
+            if (    relative_rank(Us, s) < RANK_5
+                && (pos.pieces(PAWN) & (s + pawn_push(Us))))
+                score += MinorBehindPawn;
+        }
+
+        if (Pt == ROOK)
+        {
+            // Rook piece attacking enemy pawns on the same rank/file
+            if (relative_rank(Us, s) >= RANK_5)
+            {
+                Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
+                if (pawns)
+                    score += popcount<Max15>(pawns) * RookOnPawn;
+            }
+
+            // Give a bonus for a rook on a open or semi-open file
+            if (ei.pi->semiopen_file(Us, file_of(s)))
+                score += ei.pi->semiopen_file(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
+
+            if (mob > 3 || ei.pi->semiopen_file(Us, file_of(s)))
+                continue;
+
+            Square ksq = pos.king_square(Us);
+
+            // Penalize rooks which are trapped by a king. Penalize more if the
+            // king has lost its castling capability.
+            if (   ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
+                && (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1)
+                && !ei.pi->semiopen_side(Us, file_of(ksq), file_of(s) < file_of(ksq)))
+                score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us));
+        }
+
+        // An important Chess960 pattern: A cornered bishop blocked by a friendly
+        // pawn diagonally in front of it is a very serious problem, especially
+        // when that pawn is also blocked.
+        if (   Pt == BISHOP
+            && pos.is_chess960()
+            && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
+        {
+            Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W);
+            if (pos.piece_on(s + d) == make_piece(Us, PAWN))
+                score -= !pos.empty(s + d + pawn_push(Us))                ? TrappedBishopA1H1 * 4
+                        : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
+                                                                          : TrappedBishopA1H1;
+        }
+    }
+
+    if (Trace)
+        Tracing::terms[Us][Pt] = score;
+
+    return score - evaluate_pieces<NextPt, Them, Trace>(pos, ei, mobility, mobilityArea);
+  }
+
+  template<>
+  Score evaluate_pieces<KING, WHITE, false>(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; }
+  template<>
+  Score evaluate_pieces<KING, WHITE,  true>(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; }
+
+
+  // evaluate_king() assigns bonuses and penalties to a king of a given color
+
+  template<Color Us, bool Trace>
+  Score evaluate_king(const Position& pos, const EvalInfo& ei) {
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    Bitboard undefended, b, b1, b2, safe;
+    int attackUnits;
+    const Square ksq = pos.king_square(Us);
+
+    // King shelter and enemy pawns storm
+    Score score = ei.pi->king_safety<Us>(pos, ksq);
+
+    // Main king safety evaluation
+    if (ei.kingAttackersCount[Them])
+    {
+        // Find the attacked squares around the king which have no defenders
+        // apart from the king itself
+        undefended =  ei.attackedBy[Them][ALL_PIECES]
+                    & ei.attackedBy[Us][KING]
+                    & ~(  ei.attackedBy[Us][PAWN]   | ei.attackedBy[Us][KNIGHT]
+                        | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
+                        | ei.attackedBy[Us][QUEEN]);
+
+        // Initialize the 'attackUnits' variable, which is used later on as an
+        // index to the KingDanger[] array. The initial value is based on the
+        // number and types of the enemy's attacking pieces, the number of
+        // attacked and undefended squares around our king and the quality of
+        // the pawn shelter (current 'score' value).
+        attackUnits =  std::min(20, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+                     + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended))
+                     + 2 * (ei.pinnedPieces[Us] != 0)
+                     - mg_value(score) / 32;
+
+        // Analyse the enemy's safe queen contact checks. Firstly, find the
+        // undefended squares around the king that are attacked by the enemy's
+        // queen...
+        b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
+        if (b)
+        {
+            // ...and then remove squares not supported by another enemy piece
+            b &= (  ei.attackedBy[Them][PAWN]   | ei.attackedBy[Them][KNIGHT]
+                  | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
+
+            if (b)
+                attackUnits +=  QueenContactCheck * popcount<Max15>(b);
+        }
+
+        // Analyse the enemy's safe rook contact checks. Firstly, find the
+        // undefended squares around the king that are attacked by the enemy's
+        // rooks...
+        b = undefended & ei.attackedBy[Them][ROOK] & ~pos.pieces(Them);
+
+        // Consider only squares where the enemy's rook gives check
+        b &= PseudoAttacks[ROOK][ksq];
+
+        if (b)
+        {
+            // ...and then remove squares not supported by another enemy piece
+            b &= (  ei.attackedBy[Them][PAWN]   | ei.attackedBy[Them][KNIGHT]
+                  | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
+
+            if (b)
+                attackUnits +=  RookContactCheck * popcount<Max15>(b);
+        }
+
+        // Analyse the enemy's safe distance checks for sliders and knights
+        safe = ~(pos.pieces(Them) | ei.attackedBy[Us][ALL_PIECES]);
+
+        b1 = pos.attacks_from<ROOK>(ksq) & safe;
+        b2 = pos.attacks_from<BISHOP>(ksq) & safe;
+
+        // Enemy queen safe checks
+        b = (b1 | b2) & ei.attackedBy[Them][QUEEN];
+        if (b)
+            attackUnits += QueenCheck * popcount<Max15>(b);
+
+        // Enemy rooks safe checks
+        b = b1 & ei.attackedBy[Them][ROOK];
+        if (b)
+            attackUnits += RookCheck * popcount<Max15>(b);
+
+        // Enemy bishops safe checks
+        b = b2 & ei.attackedBy[Them][BISHOP];
+        if (b)
+            attackUnits += BishopCheck * popcount<Max15>(b);
+
+        // Enemy knights safe checks
+        b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe;
+        if (b)
+            attackUnits += KnightCheck * popcount<Max15>(b);
+
+        // To index KingDanger[] attackUnits must be in [0, 99] range
+        attackUnits = std::min(99, std::max(0, attackUnits));
+
+        // Finally, extract the king danger score from the KingDanger[]
+        // array and subtract the score from evaluation.
+        score -= KingDanger[attackUnits];
+    }
+
+    if (Trace)
+        Tracing::terms[Us][KING] = score;
+
+    return score;
+  }
+
+
+  // evaluate_threats() assigns bonuses according to the type of attacking piece
+
+  template<Color Us, bool Trace>
+  Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    enum { Minor, Major };
+
+    // Enemies not defended by a pawn and under our attack
+    Bitboard b, weakEnemies =   pos.pieces(Them)
+                             & ~ei.attackedBy[Them][PAWN]
+                             &  ei.attackedBy[Us][ALL_PIECES];
+    if (!weakEnemies)
+        return SCORE_ZERO;
+
+    Score score = SCORE_ZERO;
+
+    b = weakEnemies & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+    if (b)
+        score += Threat[Minor][type_of(pos.piece_on(lsb(b)))];
+
+    b = weakEnemies & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]);
+    if (b)
+        score += Threat[Major][type_of(pos.piece_on(lsb(b)))];
+
+    b = weakEnemies & ~ei.attackedBy[Them][ALL_PIECES];
+    if (b)
+        score += more_than_one(b) ? Hanging * popcount<Max15>(b) : Hanging;
+
+    if (Trace)
+        Tracing::terms[Us][Tracing::THREAT] = score;
+
+    return score;
+  }
+
+
+  // evaluate_passed_pawns() evaluates the passed pawns of the given color
+
+  template<Color Us, bool Trace>
+  Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei) {
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    Bitboard b, squaresToQueen, defendedSquares, unsafeSquares;
+    Score score = SCORE_ZERO;
+
+    b = ei.pi->passed_pawns(Us);
+
+    while (b)
+    {
+        Square s = pop_lsb(&b);
+
+        assert(pos.pawn_passed(Us, s));
+
+        int r = relative_rank(Us, s) - RANK_2;
+        int rr = r * (r - 1);
+
+        // Base bonus based on rank
+        Value mbonus = Value(17 * rr), ebonus = Value(7 * (rr + r + 1));
+
+        if (rr)
+        {
+            Square blockSq = s + pawn_push(Us);
+
+            // Adjust bonus based on the king's proximity
+            ebonus +=  square_distance(pos.king_square(Them), blockSq) * 5 * rr
+                     - square_distance(pos.king_square(Us  ), blockSq) * 2 * rr;
+
+            // If blockSq is not the queening square then consider also a second push
+            if (relative_rank(Us, blockSq) != RANK_8)
+                ebonus -= square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr;
+
+            // If the pawn is free to advance, then increase the bonus
+            if (pos.empty(blockSq))
+            {
+                // If there is a rook or queen attacking/defending the pawn from behind,
+                // consider all the squaresToQueen. Otherwise consider only the squares
+                // in the pawn's path attacked or occupied by the enemy.
+                defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s);
+
+                Bitboard bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s);
+
+                if (!(pos.pieces(Us) & bb))
+                    defendedSquares &= ei.attackedBy[Us][ALL_PIECES];
+
+                if (!(pos.pieces(Them) & bb))
+                    unsafeSquares &= ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them);
+
+                // If there aren't any enemy attacks, assign a big bonus. Otherwise
+                // assign a smaller bonus if the block square isn't attacked.
+                int k = !unsafeSquares ? 15 : !(unsafeSquares & blockSq) ? 9 : 0;
+
+                // If the path to queen is fully defended, assign a big bonus.
+                // Otherwise assign a smaller bonus if the block square is defended.
+                if (defendedSquares == squaresToQueen)
+                    k += 6;
+
+                else if (defendedSquares & blockSq)
+                    k += 4;
+
+                mbonus += k * rr, ebonus += k * rr;
+            }
+            else if (pos.pieces(Us) & blockSq)
+                mbonus += rr * 3 + r * 2 + 3, ebonus += rr + r * 2;
+
+        } // rr != 0
+
+        if (pos.count<PAWN>(Us) < pos.count<PAWN>(Them))
+            ebonus += ebonus / 4;
+
+        score += make_score(mbonus, ebonus);
+    }
+
+    if (Trace)
+        Tracing::terms[Us][Tracing::PASSED] = apply_weight(score, Weights[PassedPawns]);
+
+    // Add the scores to the middlegame and endgame eval
+    return apply_weight(score, Weights[PassedPawns]);
+  }
+
+
+  // evaluate_unstoppable_pawns() scores the most advanced among the passed and
+  // candidate pawns. In case both players have no pieces but pawns, this is
+  // somewhat related to the possibility that pawns are unstoppable.
+
+  Score evaluate_unstoppable_pawns(Color us, const EvalInfo& ei) {
+
+    Bitboard b = ei.pi->passed_pawns(us) | ei.pi->candidate_pawns(us);
+
+    return b ? Unstoppable * int(relative_rank(us, frontmost_sq(us, b))) : SCORE_ZERO;
+  }
+
+
+  // evaluate_space() computes the space evaluation for a given side. The
+  // space evaluation is a simple bonus based on the number of safe squares
+  // available for minor pieces on the central four files on ranks 2--4. Safe
+  // squares one, two or three squares behind a friendly pawn are counted
+  // twice. Finally, the space bonus is scaled by a weight taken from the
+  // material hash table. The aim is to improve play on game opening.
+  template<Color Us>
+  int evaluate_space(const Position& pos, const EvalInfo& ei) {
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    // Find the safe squares for our pieces inside the area defined by
+    // SpaceMask[]. A square is unsafe if it is attacked by an enemy
+    // pawn, or if it is undefended and attacked by an enemy piece.
+    Bitboard safe =   SpaceMask[Us]
+                   & ~pos.pieces(Us, PAWN)
+                   & ~ei.attackedBy[Them][PAWN]
+                   & (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]);
+
+    // Find all squares which are at most three squares behind some friendly pawn
+    Bitboard behind = pos.pieces(Us, PAWN);
+    behind |= (Us == WHITE ? behind >>  8 : behind <<  8);
+    behind |= (Us == WHITE ? behind >> 16 : behind << 16);
+
+    // Since SpaceMask[Us] is fully on our half of the board
+    assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0);
+
+    // Count safe + (behind & safe) with a single popcount
+    return popcount<Full>((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
+  }
+
+
+  // do_evaluate() is the evaluation entry point, called directly from evaluate()
+
+  template<bool Trace>
+  Value do_evaluate(const Position& pos) {
+
+    assert(!pos.checkers());
+
+    EvalInfo ei;
+    Score score, mobility[2] = { SCORE_ZERO, SCORE_ZERO };
+    Thread* thisThread = pos.this_thread();
+
+    // Initialize score by reading the incrementally updated scores included
+    // in the position object (material + piece square tables).
+    // Score is computed from the point of view of white.
+    score = pos.psq_score();
+
+    // Probe the material hash table
+    ei.mi = Material::probe(pos, thisThread->materialTable, thisThread->endgames);
+    score += ei.mi->material_value();
+
+    // If we have a specialized evaluation function for the current material
+    // configuration, call it and return.
+    if (ei.mi->specialized_eval_exists())
+        return ei.mi->evaluate(pos);
+
+    // Probe the pawn hash table
+    ei.pi = Pawns::probe(pos, thisThread->pawnsTable);
+    score += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]);
+
+    // Initialize attack and king safety bitboards
+    init_eval_info<WHITE>(pos, ei);
+    init_eval_info<BLACK>(pos, ei);
+
+    ei.attackedBy[WHITE][ALL_PIECES] |= ei.attackedBy[WHITE][KING];
+    ei.attackedBy[BLACK][ALL_PIECES] |= ei.attackedBy[BLACK][KING];
+
+    // Do not include in mobility squares protected by enemy pawns or occupied by our pawns or king
+    Bitboard mobilityArea[] = { ~(ei.attackedBy[BLACK][PAWN] | pos.pieces(WHITE, PAWN, KING)),
+                                ~(ei.attackedBy[WHITE][PAWN] | pos.pieces(BLACK, PAWN, KING)) };
+
+    // Evaluate pieces and mobility
+    score += evaluate_pieces<KNIGHT, WHITE, Trace>(pos, ei, mobility, mobilityArea);
+    score += apply_weight(mobility[WHITE] - mobility[BLACK], Weights[Mobility]);
+
+    // Evaluate kings after all other pieces because we need complete attack
+    // information when computing the king safety evaluation.
+    score +=  evaluate_king<WHITE, Trace>(pos, ei)
+            - evaluate_king<BLACK, Trace>(pos, ei);
+
+    // Evaluate tactical threats, we need full attack information including king
+    score +=  evaluate_threats<WHITE, Trace>(pos, ei)
+            - evaluate_threats<BLACK, Trace>(pos, ei);
+
+    // Evaluate passed pawns, we need full attack information including king
+    score +=  evaluate_passed_pawns<WHITE, Trace>(pos, ei)
+            - evaluate_passed_pawns<BLACK, Trace>(pos, ei);
+
+    // If both sides have only pawns, score for potential unstoppable pawns
+    if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK))
+        score +=  evaluate_unstoppable_pawns(WHITE, ei)
+                - evaluate_unstoppable_pawns(BLACK, ei);
+
+    // Evaluate space for both sides, only in middlegame
+    if (ei.mi->space_weight())
+    {
+        int s = evaluate_space<WHITE>(pos, ei) - evaluate_space<BLACK>(pos, ei);
+        score += apply_weight(s * ei.mi->space_weight(), Weights[Space]);
+    }
+
+    // Scale winning side if position is more drawish than it appears
+    ScaleFactor sf = eg_value(score) > VALUE_DRAW ? ei.mi->scale_factor(pos, WHITE)
+                                                  : ei.mi->scale_factor(pos, BLACK);
+
+    // If we don't already have an unusual scale factor, check for opposite
+    // colored bishop endgames, and use a lower scale for those.
+    if (    ei.mi->game_phase() < PHASE_MIDGAME
+        &&  pos.opposite_bishops()
+        && (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN))
+    {
+        // Ignoring any pawns, do both sides only have a single bishop and no
+        // other pieces?
+        if (   pos.non_pawn_material(WHITE) == BishopValueMg
+            && pos.non_pawn_material(BLACK) == BishopValueMg)
+        {
+            // Check for KBP vs KB with only a single pawn that is almost
+            // certainly a draw or at least two pawns.
+            bool one_pawn = (pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK) == 1);
+            sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
+        }
+        else
+            // Endgame with opposite-colored bishops, but also other pieces. Still
+            // a bit drawish, but not as drawish as with only the two bishops.
+             sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL);
+    }
+
+    // Interpolate between a middlegame and a (scaled by 'sf') endgame score
+    Value v =  mg_value(score) * int(ei.mi->game_phase())
+             + eg_value(score) * int(PHASE_MIDGAME - ei.mi->game_phase()) * sf / SCALE_FACTOR_NORMAL;
+
+    v /= int(PHASE_MIDGAME);
+
+    // In case of tracing add all single evaluation contributions for both white and black
+    if (Trace)
+    {
+        Tracing::add_term(Tracing::MATERIAL, pos.psq_score());
+        Tracing::add_term(Tracing::IMBALANCE, ei.mi->material_value());
+        Tracing::add_term(PAWN, ei.pi->pawns_value());
+        Tracing::add_term(Tracing::MOBILITY, apply_weight(mobility[WHITE], Weights[Mobility])
+                                           , apply_weight(mobility[BLACK], Weights[Mobility]));
+        Score w = ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei);
+        Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
+        Tracing::add_term(Tracing::SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
+        Tracing::add_term(Tracing::TOTAL, score);
+        Tracing::ei = ei;
+        Tracing::sf = sf;
+    }
+
+    return pos.side_to_move() == WHITE ? v : -v;
+  }
+
+
+  // Tracing function definitions
+
+  double Tracing::to_cp(Value v) { return double(v) / PawnValueEg; }
+
+  void Tracing::add_term(int idx, Score wScore, Score bScore) {
+
+    terms[WHITE][idx] = wScore;
+    terms[BLACK][idx] = bScore;
+  }
+
+  void Tracing::format_row(std::stringstream& ss, const char* name, int idx) {
+
+    Score wScore = terms[WHITE][idx];
+    Score bScore = terms[BLACK][idx];
+
+    switch (idx) {
+    case MATERIAL: case IMBALANCE: case PAWN: case TOTAL:
+        ss << std::setw(15) << name << " |   ---   --- |   ---   --- | "
+           << std::setw(5)  << to_cp(mg_value(wScore - bScore)) << " "
+           << std::setw(5)  << to_cp(eg_value(wScore - bScore)) << " \n";
+        break;
+    default:
+        ss << std::setw(15) << name << " | " << std::noshowpos
+           << std::setw(5)  << to_cp(mg_value(wScore)) << " "
+           << std::setw(5)  << to_cp(eg_value(wScore)) << " | "
+           << std::setw(5)  << to_cp(mg_value(bScore)) << " "
+           << std::setw(5)  << to_cp(eg_value(bScore)) << " | "
+           << std::setw(5)  << to_cp(mg_value(wScore - bScore)) << " "
+           << std::setw(5)  << to_cp(eg_value(wScore - bScore)) << " \n";
+    }
+  }
+
+  std::string Tracing::do_trace(const Position& pos) {
+
+    std::memset(terms, 0, sizeof(terms));
+
+    Value v = do_evaluate<true>(pos);
+    v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
+
+    std::stringstream ss;
+    ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
+       << "      Eval term |    White    |    Black    |    Total    \n"
+       << "                |   MG    EG  |   MG    EG  |   MG    EG  \n"
+       << "----------------+-------------+-------------+-------------\n";
+
+    format_row(ss, "Material", MATERIAL);
+    format_row(ss, "Imbalance", IMBALANCE);
+    format_row(ss, "Pawns", PAWN);
+    format_row(ss, "Knights", KNIGHT);
+    format_row(ss, "Bishops", BISHOP);
+    format_row(ss, "Rooks", ROOK);
+    format_row(ss, "Queens", QUEEN);
+    format_row(ss, "Mobility", MOBILITY);
+    format_row(ss, "King safety", KING);
+    format_row(ss, "Threats", THREAT);
+    format_row(ss, "Passed pawns", PASSED);
+    format_row(ss, "Space", SPACE);
+
+    ss << "----------------+-------------+-------------+-------------\n";
+    format_row(ss, "Total", TOTAL);
+
+    ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n";
+
+    return ss.str();
+  }
+
+} // namespace
+
+
+namespace Eval {
+
+  /// evaluate() is the main evaluation function. It returns a static evaluation
+  /// of the position always from the point of view of the side to move.
+
+  Value evaluate(const Position& pos) {
+    return do_evaluate<false>(pos) + Tempo;
+  }
+
+
+  /// trace() is like evaluate(), but instead of returning a value, it returns
+  /// a string (suitable for outputting to stdout) that contains the detailed
+  /// descriptions and values of each evaluation term. It's mainly used for
+  /// debugging.
+  std::string trace(const Position& pos) {
+    return Tracing::do_trace(pos);
+  }
+
+
+  /// init() computes evaluation weights from the corresponding UCI parameters
+  /// and setup king tables.
+
+  void init() {
+
+    const double MaxSlope = 30;
+    const double Peak = 1280;
+
+    for (int t = 0, i = 1; i < 100; ++i)
+    {
+        t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope)));
+        KingDanger[i] = apply_weight(make_score(t, 0), Weights[KingSafety]);
+    }
+  }
+
+} // namespace Eval
diff --git a/src/evaluate.h b/src/evaluate.h
new file mode 100644 (file)
index 0000000..fff2476
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef EVALUATE_H_INCLUDED
+#define EVALUATE_H_INCLUDED
+
+#include "types.h"
+
+class Position;
+
+namespace Eval {
+
+const Value Tempo = Value(17); // Must be visible to search
+
+extern void init();
+extern Value evaluate(const Position& pos);
+extern std::string trace(const Position& pos);
+
+}
+
+#endif // #ifndef EVALUATE_H_INCLUDED
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..cbb260f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+
+#include "bitboard.h"
+#include "evaluate.h"
+#include "position.h"
+#include "search.h"
+#include "thread.h"
+#include "tt.h"
+#include "ucioption.h"
+
+int main(int argc, char* argv[]) {
+
+  std::cout << engine_info() << std::endl;
+
+  UCI::init(Options);
+  Bitboards::init();
+  Position::init();
+  Bitbases::init_kpk();
+  Search::init();
+  Pawns::init();
+  Eval::init();
+  Threads.init();
+  TT.resize(Options["Hash"]);
+
+  UCI::loop(argc, argv);
+
+  Threads.exit();
+}
diff --git a/src/material.cpp b/src/material.cpp
new file mode 100644 (file)
index 0000000..b7db134
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>  // For std::min
+#include <cassert>
+#include <cstring>
+
+#include "material.h"
+
+using namespace std;
+
+namespace {
+
+  // Polynomial material balance parameters
+
+  //                      pair  pawn knight bishop rook queen
+  const int Linear[6] = { 1852, -162, -1122, -183,  249, -154 };
+
+  const int QuadraticSameSide[][PIECE_TYPE_NB] = {
+    //            OUR PIECES
+    // pair pawn knight bishop rook queen
+    {   0                               }, // Bishop pair
+    {  39,    2                         }, // Pawn
+    {  35,  271,  -4                    }, // knight      OUR PIECES
+    {   0,  105,   4,    0              }, // Bishop
+    { -27,   -2,  46,   100,  -141      }, // Rook
+    {-177,   25, 129,   142,  -137,   0 }  // Queen
+  };
+
+  const int QuadraticOppositeSide[][PIECE_TYPE_NB] = {
+    //           THEIR PIECES
+    // pair pawn knight bishop rook queen
+    {   0                               }, // Bishop pair
+    {  37,    0                         }, // Pawn
+    {  10,   62,   0                    }, // Knight      OUR PIECES
+    {  57,   64,  39,     0             }, // Bishop
+    {  50,   40,  23,   -22,    0       }, // Rook
+    {  98,  105, -39,   141,  274,    0 }  // Queen
+  };
+
+  // Endgame evaluation and scaling functions are accessed directly and not through
+  // the function maps because they correspond to more than one material hash key.
+  Endgame<KXK>   EvaluateKXK[]   = { Endgame<KXK>(WHITE),   Endgame<KXK>(BLACK) };
+
+  Endgame<KBPsK>  ScaleKBPsK[]  = { Endgame<KBPsK>(WHITE),  Endgame<KBPsK>(BLACK) };
+  Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) };
+  Endgame<KPsK>   ScaleKPsK[]   = { Endgame<KPsK>(WHITE),   Endgame<KPsK>(BLACK) };
+  Endgame<KPKP>   ScaleKPKP[]   = { Endgame<KPKP>(WHITE),   Endgame<KPKP>(BLACK) };
+
+  // Helper templates used to detect a given material distribution
+  template<Color Us> bool is_KXK(const Position& pos) {
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+    return  !more_than_one(pos.pieces(Them))
+          && pos.non_pawn_material(Us) >= RookValueMg;
+  }
+
+  template<Color Us> bool is_KBPsKs(const Position& pos) {
+    return   pos.non_pawn_material(Us) == BishopValueMg
+          && pos.count<BISHOP>(Us) == 1
+          && pos.count<PAWN  >(Us) >= 1;
+  }
+
+  template<Color Us> bool is_KQKRPs(const Position& pos) {
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+    return  !pos.count<PAWN>(Us)
+          && pos.non_pawn_material(Us) == QueenValueMg
+          && pos.count<QUEEN>(Us)  == 1
+          && pos.count<ROOK>(Them) == 1
+          && pos.count<PAWN>(Them) >= 1;
+  }
+
+  /// imbalance() calculates the imbalance by comparing the piece count of each
+  /// piece type for both colors.
+
+  template<Color Us>
+  int imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
+
+    const Color Them = (Us == WHITE ? BLACK : WHITE);
+
+    int bonus = 0;
+
+    // Second-degree polynomial material imbalance by Tord Romstad
+    for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
+    {
+        if (!pieceCount[Us][pt1])
+            continue;
+
+        int v = Linear[pt1];
+
+        for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
+            v +=  QuadraticSameSide[pt1][pt2] * pieceCount[Us][pt2]
+                + QuadraticOppositeSide[pt1][pt2] * pieceCount[Them][pt2];
+
+        bonus += pieceCount[Us][pt1] * v;
+    }
+
+    return bonus;
+  }
+
+} // namespace
+
+namespace Material {
+
+/// Material::probe() takes a position object as input, looks up a MaterialEntry
+/// object, and returns a pointer to it. If the material configuration is not
+/// already present in the table, it is computed and stored there, so we don't
+/// have to recompute everything when the same material configuration occurs again.
+
+Entry* probe(const Position& pos, Table& entries, Endgames& endgames) {
+
+  Key key = pos.material_key();
+  Entry* e = entries[key];
+
+  // If e->key matches the position's material hash key, it means that we
+  // have analysed this material configuration before, and we can simply
+  // return the information we found the last time instead of recomputing it.
+  if (e->key == key)
+      return e;
+
+  std::memset(e, 0, sizeof(Entry));
+  e->key = key;
+  e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
+  e->gamePhase = pos.game_phase();
+
+  // Let's look if we have a specialized evaluation function for this particular
+  // material configuration. Firstly we look for a fixed configuration one, then
+  // for a generic one if the previous search failed.
+  if (endgames.probe(key, e->evaluationFunction))
+      return e;
+
+  if (is_KXK<WHITE>(pos))
+  {
+      e->evaluationFunction = &EvaluateKXK[WHITE];
+      return e;
+  }
+
+  if (is_KXK<BLACK>(pos))
+  {
+      e->evaluationFunction = &EvaluateKXK[BLACK];
+      return e;
+  }
+
+  // OK, we didn't find any special evaluation function for the current
+  // material configuration. Is there a suitable scaling function?
+  //
+  // We face problems when there are several conflicting applicable
+  // scaling functions and we need to decide which one to use.
+  EndgameBase<ScaleFactor>* sf;
+
+  if (endgames.probe(key, sf))
+  {
+      e->scalingFunction[sf->color()] = sf;
+      return e;
+  }
+
+  // Generic scaling functions that refer to more than one material
+  // distribution. They should be probed after the specialized ones.
+  // Note that these ones don't return after setting the function.
+  if (is_KBPsKs<WHITE>(pos))
+      e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
+
+  if (is_KBPsKs<BLACK>(pos))
+      e->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
+
+  if (is_KQKRPs<WHITE>(pos))
+      e->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
+
+  else if (is_KQKRPs<BLACK>(pos))
+      e->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
+
+  Value npm_w = pos.non_pawn_material(WHITE);
+  Value npm_b = pos.non_pawn_material(BLACK);
+
+  if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN))
+  {
+      if (!pos.count<PAWN>(BLACK))
+      {
+          assert(pos.count<PAWN>(WHITE) >= 2);
+          e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
+      }
+      else if (!pos.count<PAWN>(WHITE))
+      {
+          assert(pos.count<PAWN>(BLACK) >= 2);
+          e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
+      }
+      else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
+      {
+          // This is a special case because we set scaling functions
+          // for both colors instead of only one.
+          e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
+          e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
+      }
+  }
+
+  // No pawns makes it difficult to win, even with a material advantage. This
+  // catches some trivial draws like KK, KBK and KNK and gives a very drawish
+  // scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
+  if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
+      e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW : npm_b <= BishopValueMg ? 4 : 12);
+
+  if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
+      e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW : npm_w <= BishopValueMg ? 4 : 12);
+
+  if (pos.count<PAWN>(WHITE) == 1 && npm_w - npm_b <= BishopValueMg)
+      e->factor[WHITE] = (uint8_t) SCALE_FACTOR_ONEPAWN;
+
+  if (pos.count<PAWN>(BLACK) == 1 && npm_b - npm_w <= BishopValueMg)
+      e->factor[BLACK] = (uint8_t) SCALE_FACTOR_ONEPAWN;
+
+  // Compute the space weight
+  if (npm_w + npm_b >= 2 * QueenValueMg + 4 * RookValueMg + 2 * KnightValueMg)
+  {
+      int minorPieceCount =  pos.count<KNIGHT>(WHITE) + pos.count<BISHOP>(WHITE)
+                           + pos.count<KNIGHT>(BLACK) + pos.count<BISHOP>(BLACK);
+
+      e->spaceWeight = make_score(minorPieceCount * minorPieceCount, 0);
+  }
+
+  // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
+  // for the bishop pair "extended piece", which allows us to be more flexible
+  // in defining bishop pair bonuses.
+  const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = {
+  { pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
+    pos.count<BISHOP>(WHITE)    , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
+  { pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
+    pos.count<BISHOP>(BLACK)    , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
+
+  e->value = (int16_t)((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16);
+  return e;
+}
+
+} // namespace Material
diff --git a/src/material.h b/src/material.h
new file mode 100644 (file)
index 0000000..f05541c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MATERIAL_H_INCLUDED
+#define MATERIAL_H_INCLUDED
+
+#include "endgame.h"
+#include "misc.h"
+#include "position.h"
+#include "types.h"
+
+namespace Material {
+
+/// Material::Entry contains various information about a material configuration.
+/// It contains a material balance evaluation, a function pointer to a special
+/// endgame evaluation function (which in most cases is NULL, meaning that the
+/// standard evaluation function will be used), and "scale factors".
+///
+/// The scale factors are used to scale the evaluation score up or down.
+/// For instance, in KRB vs KR endgames, the score is scaled down by a factor
+/// of 4, which will result in scores of absolute value less than one pawn.
+
+struct Entry {
+
+  Score material_value() const { return make_score(value, value); }
+  Score space_weight() const { return spaceWeight; }
+  Phase game_phase() const { return gamePhase; }
+  bool specialized_eval_exists() const { return evaluationFunction != NULL; }
+  Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
+
+  // scale_factor takes a position and a color as input, and returns a scale factor
+  // for the given color. We have to provide the position in addition to the color,
+  // because the scale factor need not be a constant: It can also be a function
+  // which should be applied to the position. For instance, in KBP vs K endgames,
+  // a scaling function for draws with rook pawns and wrong-colored bishops.
+
+  ScaleFactor scale_factor(const Position& pos, Color c) const {
+
+    return !scalingFunction[c] || (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE
+          ? ScaleFactor(factor[c]) : (*scalingFunction[c])(pos);
+  }
+
+  Key key;
+  int16_t value;
+  uint8_t factor[COLOR_NB];
+  EndgameBase<Value>* evaluationFunction;
+  EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB];
+  Score spaceWeight;
+  Phase gamePhase;
+};
+
+typedef HashTable<Entry, 8192> Table;
+
+Entry* probe(const Position& pos, Table& entries, Endgames& endgames);
+
+} // namespace Material
+
+#endif // #ifndef MATERIAL_H_INCLUDED
diff --git a/src/misc.cpp b/src/misc.cpp
new file mode 100644 (file)
index 0000000..b5a14db
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "misc.h"
+#include "thread.h"
+
+using namespace std;
+
+/// Version number. If Version is left empty, then compile date in the format
+/// DD-MM-YY and show in engine_info.
+static const string Version = "";
+
+
+/// engine_info() returns the full name of the current Stockfish version. This
+/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
+/// the program was compiled) or "Stockfish <Version>", depending on whether
+/// Version is empty.
+
+const string engine_info(bool to_uci) {
+
+  const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
+  string month, day, year;
+  stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
+
+  ss << "Stockfish " << Version << setfill('0');
+
+  if (Version.empty())
+  {
+      date >> month >> day >> year;
+      ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
+  }
+
+  ss << (Is64Bit ? " 64" : "")
+     << (HasPext ? " BMI2" : (HasPopCnt ? " SSE4.2" : ""))
+     << (to_uci  ? "\nid author ": " by ")
+     << "Tord Romstad, Marco Costalba and Joona Kiiski";
+
+  return ss.str();
+}
+
+
+/// Debug functions used mainly to collect run-time statistics
+
+static int64_t hits[2], means[2];
+
+void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; }
+void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); }
+void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
+
+void dbg_print() {
+
+  if (hits[0])
+      cerr << "Total " << hits[0] << " Hits " << hits[1]
+           << " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
+
+  if (means[0])
+      cerr << "Total " << means[0] << " Mean "
+           << (double)means[1] / means[0] << endl;
+}
+
+
+/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
+/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
+/// can toggle the logging of std::cout and std:cin at runtime whilst preserving
+/// usual i/o functionality, all without changing a single line of code!
+/// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
+
+struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout
+
+  Tie(streambuf* b, ofstream* f) : buf(b), file(f) {}
+
+  int sync() { return file->rdbuf()->pubsync(), buf->pubsync(); }
+  int overflow(int c) { return log(buf->sputc((char)c), "<< "); }
+  int underflow() { return buf->sgetc(); }
+  int uflow() { return log(buf->sbumpc(), ">> "); }
+
+  streambuf* buf;
+  ofstream* file;
+
+  int log(int c, const char* prefix) {
+
+    static int last = '\n';
+
+    if (last == '\n')
+        file->rdbuf()->sputn(prefix, 3);
+
+    return last = file->rdbuf()->sputc((char)c);
+  }
+};
+
+class Logger {
+
+  Logger() : in(cin.rdbuf(), &file), out(cout.rdbuf(), &file) {}
+ ~Logger() { start(false); }
+
+  ofstream file;
+  Tie in, out;
+
+public:
+  static void start(bool b) {
+
+    static Logger l;
+
+    if (b && !l.file.is_open())
+    {
+        l.file.open("io_log.txt", ifstream::out | ifstream::app);
+        cin.rdbuf(&l.in);
+        cout.rdbuf(&l.out);
+    }
+    else if (!b && l.file.is_open())
+    {
+        cout.rdbuf(l.out.buf);
+        cin.rdbuf(l.in.buf);
+        l.file.close();
+    }
+  }
+};
+
+
+/// Used to serialize access to std::cout to avoid multiple threads writing at
+/// the same time.
+
+std::ostream& operator<<(std::ostream& os, SyncCout sc) {
+
+  static Mutex m;
+
+  if (sc == IO_LOCK)
+      m.lock();
+
+  if (sc == IO_UNLOCK)
+      m.unlock();
+
+  return os;
+}
+
+
+/// Trampoline helper to avoid moving Logger to misc.h
+void start_logger(bool b) { Logger::start(b); }
+
+
+/// timed_wait() waits for msec milliseconds. It is mainly a helper to wrap
+/// the conversion from milliseconds to struct timespec, as used by pthreads.
+
+void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) {
+
+#ifdef _WIN32
+  int tm = msec;
+#else
+  timespec ts, *tm = &ts;
+  uint64_t ms = Time::now() + msec;
+
+  ts.tv_sec = ms / 1000;
+  ts.tv_nsec = (ms % 1000) * 1000000LL;
+#endif
+
+  cond_timedwait(sleepCond, sleepLock, tm);
+}
+
+
+/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
+/// function that doesn't stall the CPU waiting for data to be loaded from memory,
+/// which can be quite slow.
+#ifdef NO_PREFETCH
+
+void prefetch(char*) {}
+
+#else
+
+void prefetch(char* addr) {
+
+#  if defined(__INTEL_COMPILER)
+   // This hack prevents prefetches from being optimized away by
+   // Intel compiler. Both MSVC and gcc seem not be affected by this.
+   __asm__ ("");
+#  endif
+
+#  if defined(__INTEL_COMPILER) || defined(_MSC_VER)
+  _mm_prefetch(addr, _MM_HINT_T0);
+#  else
+  __builtin_prefetch(addr);
+#  endif
+}
+
+#endif
diff --git a/src/misc.h b/src/misc.h
new file mode 100644 (file)
index 0000000..92bde8f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MISC_H_INCLUDED
+#define MISC_H_INCLUDED
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "types.h"
+
+extern const std::string engine_info(bool to_uci = false);
+extern void timed_wait(WaitCondition&, Lock&, int);
+extern void prefetch(char* addr);
+extern void start_logger(bool b);
+
+extern void dbg_hit_on(bool b);
+extern void dbg_hit_on_c(bool c, bool b);
+extern void dbg_mean_of(int v);
+extern void dbg_print();
+
+
+struct Log : public std::ofstream {
+  Log(const std::string& f = "log.txt") : std::ofstream(f.c_str(), std::ios::out | std::ios::app) {}
+ ~Log() { if (is_open()) close(); }
+};
+
+
+namespace Time {
+  typedef int64_t point;
+  inline point now() { return system_time_to_msec(); }
+}
+
+
+template<class Entry, int Size>
+struct HashTable {
+  HashTable() : table(Size, Entry()) {}
+  Entry* operator[](Key k) { return &table[(uint32_t)k & (Size - 1)]; }
+
+private:
+  std::vector<Entry> table;
+};
+
+
+enum SyncCout { IO_LOCK, IO_UNLOCK };
+std::ostream& operator<<(std::ostream&, SyncCout);
+
+#define sync_cout std::cout << IO_LOCK
+#define sync_endl std::endl << IO_UNLOCK
+
+#endif // #ifndef MISC_H_INCLUDED
diff --git a/src/movegen.cpp b/src/movegen.cpp
new file mode 100644 (file)
index 0000000..dab830b
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cassert>
+
+#include "movegen.h"
+#include "position.h"
+
+namespace {
+
+  template<CastlingRight Cr, bool Checks, bool Chess960>
+  ExtMove* generate_castling(const Position& pos, ExtMove* mlist, Color us, const CheckInfo* ci) {
+
+    static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
+
+    if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
+        return mlist;
+
+    // After castling, the rook and king final positions are the same in Chess960
+    // as they would be in standard chess.
+    Square kfrom = pos.king_square(us);
+    Square rfrom = pos.castling_rook_square(Cr);
+    Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
+    Bitboard enemies = pos.pieces(~us);
+
+    assert(!pos.checkers());
+
+    const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E
+                              : KingSide    ? DELTA_W : DELTA_E;
+
+    for (Square s = kto; s != kfrom; s += K)
+        if (pos.attackers_to(s) & enemies)
+            return mlist;
+
+    // Because we generate only legal castling moves we need to verify that
+    // when moving the castling rook we do not discover some hidden checker.
+    // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
+    if (Chess960 && (attacks_bb<ROOK>(kto, pos.pieces() ^ rfrom) & pos.pieces(~us, ROOK, QUEEN)))
+        return mlist;
+
+    Move m = make<CASTLING>(kfrom, rfrom);
+
+    if (Checks && !pos.gives_check(m, *ci))
+        return mlist;
+
+    (mlist++)->move = m;
+
+    return mlist;
+  }
+
+
+  template<GenType Type, Square Delta>
+  inline ExtMove* generate_promotions(ExtMove* mlist, Bitboard pawnsOn7,
+                                      Bitboard target, const CheckInfo* ci) {
+
+    Bitboard b = shift_bb<Delta>(pawnsOn7) & target;
+
+    while (b)
+    {
+        Square to = pop_lsb(&b);
+
+        if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
+            (mlist++)->move = make<PROMOTION>(to - Delta, to, QUEEN);
+
+        if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
+        {
+            (mlist++)->move = make<PROMOTION>(to - Delta, to, ROOK);
+            (mlist++)->move = make<PROMOTION>(to - Delta, to, BISHOP);
+            (mlist++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
+        }
+
+        // Knight promotion is the only promotion that can give a direct check
+        // that's not already included in the queen promotion.
+        if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
+            (mlist++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
+        else
+            (void)ci; // Silence a warning under MSVC
+    }
+
+    return mlist;
+  }
+
+
+  template<Color Us, GenType Type>
+  ExtMove* generate_pawn_moves(const Position& pos, ExtMove* mlist,
+                               Bitboard target, const CheckInfo* ci) {
+
+    // Compute our parametrized parameters at compile time, named according to
+    // the point of view of white side.
+    const Color    Them     = (Us == WHITE ? BLACK    : WHITE);
+    const Bitboard TRank8BB = (Us == WHITE ? Rank8BB  : Rank1BB);
+    const Bitboard TRank7BB = (Us == WHITE ? Rank7BB  : Rank2BB);
+    const Bitboard TRank3BB = (Us == WHITE ? Rank3BB  : Rank6BB);
+    const Square   Up       = (Us == WHITE ? DELTA_N  : DELTA_S);
+    const Square   Right    = (Us == WHITE ? DELTA_NE : DELTA_SW);
+    const Square   Left     = (Us == WHITE ? DELTA_NW : DELTA_SE);
+
+    Bitboard b1, b2, dc1, dc2, emptySquares;
+
+    Bitboard pawnsOn7    = pos.pieces(Us, PAWN) &  TRank7BB;
+    Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
+
+    Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
+                        Type == CAPTURES ? target : pos.pieces(Them));
+
+    // Single and double pawn pushes, no promotions
+    if (Type != CAPTURES)
+    {
+        emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
+
+        b1 = shift_bb<Up>(pawnsNotOn7)   & emptySquares;
+        b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
+
+        if (Type == EVASIONS) // Consider only blocking squares
+        {
+            b1 &= target;
+            b2 &= target;
+        }
+
+        if (Type == QUIET_CHECKS)
+        {
+            b1 &= pos.attacks_from<PAWN>(ci->ksq, Them);
+            b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
+
+            // Add pawn pushes which give discovered check. This is possible only
+            // if the pawn is not on the same file as the enemy king, because we
+            // don't generate captures. Note that a possible discovery check
+            // promotion has been already generated amongst the captures.
+            if (pawnsNotOn7 & ci->dcCandidates)
+            {
+                dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
+                dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
+
+                b1 |= dc1;
+                b2 |= dc2;
+            }
+        }
+
+        while (b1)
+        {
+            Square to = pop_lsb(&b1);
+            (mlist++)->move = make_move(to - Up, to);
+        }
+
+        while (b2)
+        {
+            Square to = pop_lsb(&b2);
+            (mlist++)->move = make_move(to - Up - Up, to);
+        }
+    }
+
+    // Promotions and underpromotions
+    if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB)))
+    {
+        if (Type == CAPTURES)
+            emptySquares = ~pos.pieces();
+
+        if (Type == EVASIONS)
+            emptySquares &= target;
+
+        mlist = generate_promotions<Type, Right>(mlist, pawnsOn7, enemies, ci);
+        mlist = generate_promotions<Type, Left >(mlist, pawnsOn7, enemies, ci);
+        mlist = generate_promotions<Type, Up>(mlist, pawnsOn7, emptySquares, ci);
+    }
+
+    // Standard and en-passant captures
+    if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
+    {
+        b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
+        b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
+
+        while (b1)
+        {
+            Square to = pop_lsb(&b1);
+            (mlist++)->move = make_move(to - Right, to);
+        }
+
+        while (b2)
+        {
+            Square to = pop_lsb(&b2);
+            (mlist++)->move = make_move(to - Left, to);
+        }
+
+        if (pos.ep_square() != SQ_NONE)
+        {
+            assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
+
+            // An en passant capture can be an evasion only if the checking piece
+            // is the double pushed pawn and so is in the target. Otherwise this
+            // is a discovery check and we are forced to do otherwise.
+            if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
+                return mlist;
+
+            b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
+
+            assert(b1);
+
+            while (b1)
+                (mlist++)->move = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
+        }
+    }
+
+    return mlist;
+  }
+
+
+  template<PieceType Pt, bool Checks> FORCE_INLINE
+  ExtMove* generate_moves(const Position& pos, ExtMove* mlist, Color us,
+                          Bitboard target, const CheckInfo* ci) {
+
+    assert(Pt != KING && Pt != PAWN);
+
+    const Square* pl = pos.list<Pt>(us);
+
+    for (Square from = *pl; from != SQ_NONE; from = *++pl)
+    {
+        if (Checks)
+        {
+            if (    (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
+                && !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt]))
+                continue;
+
+            if (unlikely(ci->dcCandidates) && (ci->dcCandidates & from))
+                continue;
+        }
+
+        Bitboard b = pos.attacks_from<Pt>(from) & target;
+
+        if (Checks)
+            b &= ci->checkSq[Pt];
+
+        while (b)
+            (mlist++)->move = make_move(from, pop_lsb(&b));
+    }
+
+    return mlist;
+  }
+
+
+  template<Color Us, GenType Type> FORCE_INLINE
+  ExtMove* generate_all(const Position& pos, ExtMove* mlist, Bitboard target,
+                        const CheckInfo* ci = NULL) {
+
+    const bool Checks = Type == QUIET_CHECKS;
+
+    mlist = generate_pawn_moves<Us, Type>(pos, mlist, target, ci);
+    mlist = generate_moves<KNIGHT, Checks>(pos, mlist, Us, target, ci);
+    mlist = generate_moves<BISHOP, Checks>(pos, mlist, Us, target, ci);
+    mlist = generate_moves<  ROOK, Checks>(pos, mlist, Us, target, ci);
+    mlist = generate_moves< QUEEN, Checks>(pos, mlist, Us, target, ci);
+
+    if (Type != QUIET_CHECKS && Type != EVASIONS)
+    {
+        Square ksq = pos.king_square(Us);
+        Bitboard b = pos.attacks_from<KING>(ksq) & target;
+        while (b)
+            (mlist++)->move = make_move(ksq, pop_lsb(&b));
+    }
+
+    if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
+    {
+        if (pos.is_chess960())
+        {
+            mlist = generate_castling<MakeCastling<Us,  KING_SIDE>::right, Checks, true>(pos, mlist, Us, ci);
+            mlist = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, mlist, Us, ci);
+        }
+        else
+        {
+            mlist = generate_castling<MakeCastling<Us,  KING_SIDE>::right, Checks, false>(pos, mlist, Us, ci);
+            mlist = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, mlist, Us, ci);
+        }
+    }
+
+    return mlist;
+  }
+
+
+} // namespace
+
+
+/// generate<CAPTURES> generates all pseudo-legal captures and queen
+/// promotions. Returns a pointer to the end of the move list.
+///
+/// generate<QUIETS> generates all pseudo-legal non-captures and
+/// underpromotions. Returns a pointer to the end of the move list.
+///
+/// generate<NON_EVASIONS> generates all pseudo-legal captures and
+/// non-captures. Returns a pointer to the end of the move list.
+
+template<GenType Type>
+ExtMove* generate(const Position& pos, ExtMove* mlist) {
+
+  assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS);
+  assert(!pos.checkers());
+
+  Color us = pos.side_to_move();
+
+  Bitboard target = Type == CAPTURES     ?  pos.pieces(~us)
+                  : Type == QUIETS       ? ~pos.pieces()
+                  : Type == NON_EVASIONS ? ~pos.pieces(us) : 0;
+
+  return us == WHITE ? generate_all<WHITE, Type>(pos, mlist, target)
+                     : generate_all<BLACK, Type>(pos, mlist, target);
+}
+
+// Explicit template instantiations
+template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
+template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
+template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
+
+
+/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
+/// underpromotions that give check. Returns a pointer to the end of the move list.
+template<>
+ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* mlist) {
+
+  assert(!pos.checkers());
+
+  Color us = pos.side_to_move();
+  CheckInfo ci(pos);
+  Bitboard dc = ci.dcCandidates;
+
+  while (dc)
+  {
+     Square from = pop_lsb(&dc);
+     PieceType pt = type_of(pos.piece_on(from));
+
+     if (pt == PAWN)
+         continue; // Will be generated together with direct checks
+
+     Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces();
+
+     if (pt == KING)
+         b &= ~PseudoAttacks[QUEEN][ci.ksq];
+
+     while (b)
+         (mlist++)->move = make_move(from, pop_lsb(&b));
+  }
+
+  return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, mlist, ~pos.pieces(), &ci)
+                     : generate_all<BLACK, QUIET_CHECKS>(pos, mlist, ~pos.pieces(), &ci);
+}
+
+
+/// generate<EVASIONS> generates all pseudo-legal check evasions when the side
+/// to move is in check. Returns a pointer to the end of the move list.
+template<>
+ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* mlist) {
+
+  assert(pos.checkers());
+
+  Color us = pos.side_to_move();
+  Square ksq = pos.king_square(us);
+  Bitboard sliderAttacks = 0;
+  Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
+
+  // Find all the squares attacked by slider checkers. We will remove them from
+  // the king evasions in order to skip known illegal moves, which avoids any
+  // useless legality checks later on.
+  while (sliders)
+  {
+      Square checksq = pop_lsb(&sliders);
+      sliderAttacks |= LineBB[checksq][ksq] ^ checksq;
+  }
+
+  // Generate evasions for king, capture and non capture moves
+  Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
+  while (b)
+      (mlist++)->move = make_move(ksq, pop_lsb(&b));
+
+  if (more_than_one(pos.checkers()))
+      return mlist; // Double check, only a king move can save the day
+
+  // Generate blocking evasions or captures of the checking piece
+  Square checksq = lsb(pos.checkers());
+  Bitboard target = between_bb(checksq, ksq) | checksq;
+
+  return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, mlist, target)
+                     : generate_all<BLACK, EVASIONS>(pos, mlist, target);
+}
+
+
+/// generate<LEGAL> generates all the legal moves in the given position
+
+template<>
+ExtMove* generate<LEGAL>(const Position& pos, ExtMove* mlist) {
+
+  ExtMove *end, *cur = mlist;
+  Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
+  Square ksq = pos.king_square(pos.side_to_move());
+
+  end = pos.checkers() ? generate<EVASIONS>(pos, mlist)
+                       : generate<NON_EVASIONS>(pos, mlist);
+  while (cur != end)
+      if (   (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT)
+          && !pos.legal(cur->move, pinned))
+          cur->move = (--end)->move;
+      else
+          ++cur;
+
+  return end;
+}
diff --git a/src/movegen.h b/src/movegen.h
new file mode 100644 (file)
index 0000000..c18fa07
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MOVEGEN_H_INCLUDED
+#define MOVEGEN_H_INCLUDED
+
+#include "types.h"
+
+enum GenType {
+  CAPTURES,
+  QUIETS,
+  QUIET_CHECKS,
+  EVASIONS,
+  NON_EVASIONS,
+  LEGAL
+};
+
+class Position;
+
+template<GenType>
+ExtMove* generate(const Position& pos, ExtMove* mlist);
+
+/// The MoveList struct is a simple wrapper around generate(). It sometimes comes
+/// in handy to use this class instead of the low level generate() function.
+template<GenType T>
+struct MoveList {
+
+  explicit MoveList(const Position& pos) : cur(mlist), last(generate<T>(pos, mlist)) { last->move = MOVE_NONE; }
+  void operator++() { ++cur; }
+  Move operator*() const { return cur->move; }
+  size_t size() const { return last - mlist; }
+  bool contains(Move m) const {
+    for (const ExtMove* it(mlist); it != last; ++it) if (it->move == m) return true;
+    return false;
+  }
+
+private:
+  ExtMove mlist[MAX_MOVES];
+  ExtMove *cur, *last;
+};
+
+#endif // #ifndef MOVEGEN_H_INCLUDED
diff --git a/src/movepick.cpp b/src/movepick.cpp
new file mode 100644 (file)
index 0000000..95172b9
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cassert>
+
+#include "movepick.h"
+#include "thread.h"
+
+namespace {
+
+  enum Stages {
+    MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1,
+    EVASION,     EVASIONS_S2,
+    QSEARCH_0,   CAPTURES_S3, QUIET_CHECKS_S3,
+    QSEARCH_1,   CAPTURES_S4,
+    PROBCUT,     CAPTURES_S5,
+    RECAPTURE,   CAPTURES_S6,
+    STOP
+  };
+
+  // Our insertion sort, which is guaranteed (and also needed) to be stable
+  void insertion_sort(ExtMove* begin, ExtMove* end)
+  {
+    ExtMove tmp, *p, *q;
+
+    for (p = begin + 1; p < end; ++p)
+    {
+        tmp = *p;
+        for (q = p; q != begin && *(q-1) < tmp; --q)
+            *q = *(q-1);
+        *q = tmp;
+    }
+  }
+
+  // Unary predicate used by std::partition to split positive values from remaining
+  // ones so as to sort the two sets separately, with the second sort delayed.
+  inline bool has_positive_value(const ExtMove& ms) { return ms.value > 0; }
+
+  // Picks the best move in the range (begin, end) and moves it to the front.
+  // It's faster than sorting all the moves in advance when there are few
+  // moves e.g. possible captures.
+  inline ExtMove* pick_best(ExtMove* begin, ExtMove* end)
+  {
+      std::swap(*begin, *std::max_element(begin, end));
+      return begin;
+  }
+}
+
+
+/// Constructors of the MovePicker class. As arguments we pass information
+/// to help it to return the (presumably) good moves first, to decide which
+/// moves to return (in the quiescence search, for instance, we only want to
+/// search captures, promotions and some checks) and how important good move
+/// ordering is at the current node.
+
+MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
+                       Move* cm, Move* fm, Search::Stack* s) : pos(p), history(h), depth(d) {
+
+  assert(d > DEPTH_ZERO);
+
+  cur = end = moves;
+  endBadCaptures = moves + MAX_MOVES - 1;
+  countermoves = cm;
+  followupmoves = fm;
+  ss = s;
+
+  if (pos.checkers())
+      stage = EVASION;
+
+  else
+      stage = MAIN_SEARCH;
+
+  ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
+  end += (ttMove != MOVE_NONE);
+}
+
+MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
+                       Square s) : pos(p), history(h), cur(moves), end(moves) {
+
+  assert(d <= DEPTH_ZERO);
+
+  if (pos.checkers())
+      stage = EVASION;
+
+  else if (d > DEPTH_QS_NO_CHECKS)
+      stage = QSEARCH_0;
+
+  else if (d > DEPTH_QS_RECAPTURES)
+  {
+      stage = QSEARCH_1;
+
+      // Skip TT move if is not a capture or a promotion. This avoids qsearch
+      // tree explosion due to a possible perpetual check or similar rare cases
+      // when TT table is full.
+      if (ttm && !pos.capture_or_promotion(ttm))
+          ttm = MOVE_NONE;
+  }
+  else
+  {
+      stage = RECAPTURE;
+      recaptureSquare = s;
+      ttm = MOVE_NONE;
+  }
+
+  ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
+  end += (ttMove != MOVE_NONE);
+}
+
+MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, PieceType pt)
+                       : pos(p), history(h), cur(moves), end(moves) {
+
+  assert(!pos.checkers());
+
+  stage = PROBCUT;
+
+  // In ProbCut we generate only captures that are better than the parent's
+  // captured piece.
+  captureThreshold = PieceValue[MG][pt];
+  ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
+
+  if (ttMove && (!pos.capture(ttMove) || pos.see(ttMove) <= captureThreshold))
+      ttMove = MOVE_NONE;
+
+  end += (ttMove != MOVE_NONE);
+}
+
+
+/// score() assign a numerical value to each move in a move list. The moves with
+/// highest values will be picked first.
+template<>
+void MovePicker::score<CAPTURES>() {
+  // Winning and equal captures in the main search are ordered by MVV/LVA.
+  // Suprisingly, this appears to perform slightly better than SEE based
+  // move ordering. The reason is probably that in a position with a winning
+  // capture, capturing a more valuable (but sufficiently defended) piece
+  // first usually doesn't hurt. The opponent will have to recapture, and
+  // the hanging piece will still be hanging (except in the unusual cases
+  // where it is possible to recapture with the hanging piece). Exchanging
+  // big pieces before capturing a hanging piece probably helps to reduce
+  // the subtree size.
+  // In main search we want to push captures with negative SEE values to the
+  // badCaptures[] array, but instead of doing it now we delay until the move
+  // has been picked up in pick_move_from_list(). This way we save some SEE
+  // calls in case we get a cutoff.
+  Move m;
+
+  for (ExtMove* it = moves; it != end; ++it)
+  {
+      m = it->move;
+      it->value =  PieceValue[MG][pos.piece_on(to_sq(m))]
+                 - Value(type_of(pos.moved_piece(m)));
+
+      if (type_of(m) == ENPASSANT)
+          it->value += PieceValue[MG][PAWN];
+
+      else if (type_of(m) == PROMOTION)
+          it->value += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN];
+  }
+}
+
+template<>
+void MovePicker::score<QUIETS>() {
+
+  Move m;
+
+  for (ExtMove* it = moves; it != end; ++it)
+  {
+      m = it->move;
+      it->value = history[pos.moved_piece(m)][to_sq(m)];
+  }
+}
+
+template<>
+void MovePicker::score<EVASIONS>() {
+  // Try good captures ordered by MVV/LVA, then non-captures if destination square
+  // is not under attack, ordered by history value, then bad-captures and quiet
+  // moves with a negative SEE. This last group is ordered by the SEE value.
+  Move m;
+  Value see;
+
+  for (ExtMove* it = moves; it != end; ++it)
+  {
+      m = it->move;
+      if ((see = pos.see_sign(m)) < VALUE_ZERO)
+          it->value = see - HistoryStats::Max; // At the bottom
+
+      else if (pos.capture(m))
+          it->value =  PieceValue[MG][pos.piece_on(to_sq(m))]
+                     - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
+      else
+          it->value = history[pos.moved_piece(m)][to_sq(m)];
+  }
+}
+
+
+/// generate_next_stage() generates, scores and sorts the next bunch of moves,
+/// when there are no more moves to try for the current stage.
+
+void MovePicker::generate_next_stage() {
+
+  cur = moves;
+
+  switch (++stage) {
+
+  case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6:
+      end = generate<CAPTURES>(pos, moves);
+      score<CAPTURES>();
+      return;
+
+  case KILLERS_S1:
+      cur = killers;
+      end = cur + 2;
+
+      killers[0].move = ss->killers[0];
+      killers[1].move = ss->killers[1];
+      killers[2].move = killers[3].move = MOVE_NONE;
+      killers[4].move = killers[5].move = MOVE_NONE;
+
+      // Please note that following code is racy and could yield to rare (less
+      // than 1 out of a million) duplicated entries in SMP case. This is harmless.
+
+      // Be sure countermoves are different from killers
+      for (int i = 0; i < 2; ++i)
+          if (   countermoves[i] != (cur+0)->move
+              && countermoves[i] != (cur+1)->move)
+              (end++)->move = countermoves[i];
+
+      // Be sure followupmoves are different from killers and countermoves
+      for (int i = 0; i < 2; ++i)
+          if (   followupmoves[i] != (cur+0)->move
+              && followupmoves[i] != (cur+1)->move
+              && followupmoves[i] != (cur+2)->move
+              && followupmoves[i] != (cur+3)->move)
+              (end++)->move = followupmoves[i];
+      return;
+
+  case QUIETS_1_S1:
+      endQuiets = end = generate<QUIETS>(pos, moves);
+      score<QUIETS>();
+      end = std::partition(cur, end, has_positive_value);
+      insertion_sort(cur, end);
+      return;
+
+  case QUIETS_2_S1:
+      cur = end;
+      end = endQuiets;
+      if (depth >= 3 * ONE_PLY)
+          insertion_sort(cur, end);
+      return;
+
+  case BAD_CAPTURES_S1:
+      // Just pick them in reverse order to get MVV/LVA ordering
+      cur = moves + MAX_MOVES - 1;
+      end = endBadCaptures;
+      return;
+
+  case EVASIONS_S2:
+      end = generate<EVASIONS>(pos, moves);
+      if (end > moves + 1)
+          score<EVASIONS>();
+      return;
+
+  case QUIET_CHECKS_S3:
+      end = generate<QUIET_CHECKS>(pos, moves);
+      return;
+
+  case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE:
+      stage = STOP;
+      /* Fall through */
+
+  case STOP:
+      end = cur + 1; // Avoid another next_phase() call
+      return;
+
+  default:
+      assert(false);
+  }
+}
+
+
+/// next_move() is the most important method of the MovePicker class. It returns
+/// a new pseudo legal move every time it is called, until there are no more moves
+/// left. It picks the move with the biggest value from a list of generated moves
+/// taking care not to return the ttMove if it has already been searched.
+template<>
+Move MovePicker::next_move<false>() {
+
+  Move move;
+
+  while (true)
+  {
+      while (cur == end)
+          generate_next_stage();
+
+      switch (stage) {
+
+      case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT:
+          ++cur;
+          return ttMove;
+
+      case CAPTURES_S1:
+          move = pick_best(cur++, end)->move;
+          if (move != ttMove)
+          {
+              if (pos.see_sign(move) >= VALUE_ZERO)
+                  return move;
+
+              // Losing capture, move it to the tail of the array
+              (endBadCaptures--)->move = move;
+          }
+          break;
+
+      case KILLERS_S1:
+          move = (cur++)->move;
+          if (    move != MOVE_NONE
+              &&  move != ttMove
+              &&  pos.pseudo_legal(move)
+              && !pos.capture(move))
+              return move;
+          break;
+
+      case QUIETS_1_S1: case QUIETS_2_S1:
+          move = (cur++)->move;
+          if (   move != ttMove
+              && move != killers[0].move
+              && move != killers[1].move
+              && move != killers[2].move
+              && move != killers[3].move
+              && move != killers[4].move
+              && move != killers[5].move)
+              return move;
+          break;
+
+      case BAD_CAPTURES_S1:
+          return (cur--)->move;
+
+      case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4:
+          move = pick_best(cur++, end)->move;
+          if (move != ttMove)
+              return move;
+          break;
+
+      case CAPTURES_S5:
+           move = pick_best(cur++, end)->move;
+           if (move != ttMove && pos.see(move) > captureThreshold)
+               return move;
+           break;
+
+      case CAPTURES_S6:
+          move = pick_best(cur++, end)->move;
+          if (to_sq(move) == recaptureSquare)
+              return move;
+          break;
+
+      case QUIET_CHECKS_S3:
+          move = (cur++)->move;
+          if (move != ttMove)
+              return move;
+          break;
+
+      case STOP:
+          return MOVE_NONE;
+
+      default:
+          assert(false);
+      }
+  }
+}
+
+
+/// Version of next_move() to use at split point nodes where the move is grabbed
+/// from the split point's shared MovePicker object. This function is not thread
+/// safe so must be lock protected by the caller.
+template<>
+Move MovePicker::next_move<true>() { return ss->splitPoint->movePicker->next_move<false>(); }
diff --git a/src/movepick.h b/src/movepick.h
new file mode 100644 (file)
index 0000000..c512d13
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MOVEPICK_H_INCLUDED
+#define MOVEPICK_H_INCLUDED
+
+#include <algorithm> // For std::max
+#include <cstring>   // For std::memset
+
+#include "movegen.h"
+#include "position.h"
+#include "search.h"
+#include "types.h"
+
+
+/// The Stats struct stores moves statistics. According to the template parameter
+/// the class can store History, Gains and Countermoves. History records how often
+/// different moves have been successful or unsuccessful during the current search
+/// and is used for reduction and move ordering decisions. Gains records the move's
+/// best evaluation gain from one ply to the next and is used for pruning decisions.
+/// Countermoves store the move that refute a previous one. Entries are stored
+/// using only the moving piece and destination square, hence two moves with
+/// different origin but same destination and piece will be considered identical.
+template<bool Gain, typename T>
+struct Stats {
+
+  static const Value Max = Value(2000);
+
+  const T* operator[](Piece pc) const { return table[pc]; }
+  void clear() { std::memset(table, 0, sizeof(table)); }
+
+  void update(Piece pc, Square to, Move m) {
+
+    if (m == table[pc][to].first)
+        return;
+
+    table[pc][to].second = table[pc][to].first;
+    table[pc][to].first = m;
+  }
+
+  void update(Piece pc, Square to, Value v) {
+
+    if (Gain)
+        table[pc][to] = std::max(v, table[pc][to] - 1);
+
+    else if (abs(table[pc][to] + v) < Max)
+        table[pc][to] +=  v;
+  }
+
+private:
+  T table[PIECE_NB][SQUARE_NB];
+};
+
+typedef Stats< true, Value> GainsStats;
+typedef Stats<false, Value> HistoryStats;
+typedef Stats<false, std::pair<Move, Move> > MovesStats;
+
+
+/// MovePicker class is used to pick one pseudo legal move at a time from the
+/// current position. The most important method is next_move(), which returns a
+/// new pseudo legal move each time it is called, until there are no moves left,
+/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
+/// beta algorithm, MovePicker attempts to return the moves which are most likely
+/// to get a cut-off first.
+
+class MovePicker {
+
+  MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
+
+public:
+  MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
+  MovePicker(const Position&, Move, const HistoryStats&, PieceType);
+  MovePicker(const Position&, Move, Depth, const HistoryStats&, Move*, Move*, Search::Stack*);
+
+  template<bool SpNode> Move next_move();
+
+private:
+  template<GenType> void score();
+  void generate_next_stage();
+
+  const Position& pos;
+  const HistoryStats& history;
+  Search::Stack* ss;
+  Move* countermoves;
+  Move* followupmoves;
+  Depth depth;
+  Move ttMove;
+  ExtMove killers[6];
+  Square recaptureSquare;
+  Value captureThreshold;
+  int stage;
+  ExtMove *cur, *end, *endQuiets, *endBadCaptures;
+  ExtMove moves[MAX_MOVES];
+};
+
+#endif // #ifndef MOVEPICK_H_INCLUDED
diff --git a/src/notation.cpp b/src/notation.cpp
new file mode 100644 (file)
index 0000000..cace78b
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cassert>
+#include <iomanip>
+#include <sstream>
+#include <stack>
+
+#include "movegen.h"
+#include "notation.h"
+#include "position.h"
+
+using namespace std;
+
+static const char* PieceToChar[COLOR_NB] = { " PNBRQK", " pnbrqk" };
+
+
+/// score_to_uci() converts a value to a string suitable for use with the UCI
+/// protocol specifications:
+///
+/// cp <x>     The score from the engine's point of view in centipawns.
+/// mate <y>   Mate in y moves, not plies. If the engine is getting mated
+///            use negative values for y.
+
+string score_to_uci(Value v, Value alpha, Value beta) {
+
+  stringstream ss;
+
+  if (abs(v) < VALUE_MATE_IN_MAX_PLY)
+      ss << "cp " << v * 100 / PawnValueEg;
+  else
+      ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
+
+  ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
+
+  return ss.str();
+}
+
+
+/// move_to_uci() converts a move to a string in coordinate notation
+/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we print
+/// in the e1g1 notation in normal chess mode, and in e1h1 notation in chess960
+/// mode. Internally castling moves are always encoded as "king captures rook".
+
+const string move_to_uci(Move m, bool chess960) {
+
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+
+  if (m == MOVE_NONE)
+      return "(none)";
+
+  if (m == MOVE_NULL)
+      return "0000";
+
+  if (type_of(m) == CASTLING && !chess960)
+      to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
+
+  string move = to_string(from) + to_string(to);
+
+  if (type_of(m) == PROMOTION)
+      move += PieceToChar[BLACK][promotion_type(m)]; // Lower case
+
+  return move;
+}
+
+
+/// move_from_uci() takes a position and a string representing a move in
+/// simple coordinate notation and returns an equivalent legal Move if any.
+
+Move move_from_uci(const Position& pos, string& str) {
+
+  if (str.length() == 5) // Junior could send promotion piece in uppercase
+      str[4] = char(tolower(str[4]));
+
+  for (MoveList<LEGAL> it(pos); *it; ++it)
+      if (str == move_to_uci(*it, pos.is_chess960()))
+          return *it;
+
+  return MOVE_NONE;
+}
+
+
+/// move_to_san() takes a position and a legal Move as input and returns its
+/// short algebraic notation representation.
+
+const string move_to_san(Position& pos, Move m) {
+
+  if (m == MOVE_NONE)
+      return "(none)";
+
+  if (m == MOVE_NULL)
+      return "(null)";
+
+  assert(MoveList<LEGAL>(pos).contains(m));
+
+  Bitboard others, b;
+  string san;
+  Color us = pos.side_to_move();
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+  Piece pc = pos.piece_on(from);
+  PieceType pt = type_of(pc);
+
+  if (type_of(m) == CASTLING)
+      san = to > from ? "O-O" : "O-O-O";
+  else
+  {
+      if (pt != PAWN)
+      {
+          san = PieceToChar[WHITE][pt]; // Upper case
+
+          // A disambiguation occurs if we have more then one piece of type 'pt'
+          // that can reach 'to' with a legal move.
+          others = b = (pos.attacks_from(pc, to) & pos.pieces(us, pt)) ^ from;
+
+          while (b)
+          {
+              Square s = pop_lsb(&b);
+              if (!pos.legal(make_move(s, to), pos.pinned_pieces(us)))
+                  others ^= s;
+          }
+
+          if (!others)
+          { /* Disambiguation is not needed */ }
+
+          else if (!(others & file_bb(from)))
+              san += to_char(file_of(from));
+
+          else if (!(others & rank_bb(from)))
+              san += to_char(rank_of(from));
+
+          else
+              san += to_string(from);
+      }
+      else if (pos.capture(m))
+          san = to_char(file_of(from));
+
+      if (pos.capture(m))
+          san += 'x';
+
+      san += to_string(to);
+
+      if (type_of(m) == PROMOTION)
+          san += string("=") + PieceToChar[WHITE][promotion_type(m)];
+  }
+
+  if (pos.gives_check(m, CheckInfo(pos)))
+  {
+      StateInfo st;
+      pos.do_move(m, st);
+      san += MoveList<LEGAL>(pos).size() ? "+" : "#";
+      pos.undo_move(m);
+  }
+
+  return san;
+}
+
+
+/// pretty_pv() formats human-readable search information, typically to be
+/// appended to the search log file. It uses the two helpers below to pretty
+/// format the time and score respectively.
+
+static string format(int64_t msecs) {
+
+  const int MSecMinute = 1000 * 60;
+  const int MSecHour   = 1000 * 60 * 60;
+
+  int64_t hours   =   msecs / MSecHour;
+  int64_t minutes =  (msecs % MSecHour) / MSecMinute;
+  int64_t seconds = ((msecs % MSecHour) % MSecMinute) / 1000;
+
+  stringstream ss;
+
+  if (hours)
+      ss << hours << ':';
+
+  ss << setfill('0') << setw(2) << minutes << ':' << setw(2) << seconds;
+
+  return ss.str();
+}
+
+static string format(Value v) {
+
+  stringstream ss;
+
+  if (v >= VALUE_MATE_IN_MAX_PLY)
+      ss << "#" << (VALUE_MATE - v + 1) / 2;
+
+  else if (v <= VALUE_MATED_IN_MAX_PLY)
+      ss << "-#" << (VALUE_MATE + v) / 2;
+
+  else
+      ss << setprecision(2) << fixed << showpos << double(v) / PawnValueEg;
+
+  return ss.str();
+}
+
+string pretty_pv(Position& pos, int depth, Value value, int64_t msecs, Move pv[]) {
+
+  const uint64_t K = 1000;
+  const uint64_t M = 1000000;
+
+  std::stack<StateInfo> st;
+  Move* m = pv;
+  string san, str, padding;
+  stringstream ss;
+
+  ss << setw(2) << depth << setw(8) << format(value) << setw(8) << format(msecs);
+
+  if (pos.nodes_searched() < M)
+      ss << setw(8) << pos.nodes_searched() / 1 << "  ";
+
+  else if (pos.nodes_searched() < K * M)
+      ss << setw(7) << pos.nodes_searched() / K << "K  ";
+
+  else
+      ss << setw(7) << pos.nodes_searched() / M << "M  ";
+
+  str = ss.str();
+  padding = string(str.length(), ' ');
+
+  while (*m != MOVE_NONE)
+  {
+      san = move_to_san(pos, *m) + ' ';
+
+      if ((str.length() + san.length()) % 80 <= san.length()) // Exceed 80 cols
+          str += "\n" + padding;
+
+      str += san;
+
+      st.push(StateInfo());
+      pos.do_move(*m++, st.top());
+  }
+
+  while (m != pv)
+      pos.undo_move(*--m);
+
+  return str;
+}
diff --git a/src/notation.h b/src/notation.h
new file mode 100644 (file)
index 0000000..a8168c5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NOTATION_H_INCLUDED
+#define NOTATION_H_INCLUDED
+
+#include <string>
+
+#include "types.h"
+
+class Position;
+
+std::string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
+Move move_from_uci(const Position& pos, std::string& str);
+const std::string move_to_uci(Move m, bool chess960);
+const std::string move_to_san(Position& pos, Move m);
+std::string pretty_pv(Position& pos, int depth, Value score, int64_t msecs, Move pv[]);
+
+inline char to_char(File f, bool tolower = true) {
+  return char(f - FILE_A + (tolower ? 'a' : 'A'));
+}
+
+inline char to_char(Rank r) {
+  return char(r - RANK_1 + '1');
+}
+
+inline const std::string to_string(Square s) {
+  char ch[] = { to_char(file_of(s)), to_char(rank_of(s)), 0 };
+  return ch;
+}
+
+#endif // #ifndef NOTATION_H_INCLUDED
diff --git a/src/pawns.cpp b/src/pawns.cpp
new file mode 100644 (file)
index 0000000..d137c5f
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cassert>
+
+#include "bitboard.h"
+#include "bitcount.h"
+#include "pawns.h"
+#include "position.h"
+
+namespace {
+
+  #define V Value
+  #define S(mg, eg) make_score(mg, eg)
+
+  // Doubled pawn penalty by file
+  const Score Doubled[FILE_NB] = {
+    S(13, 43), S(20, 48), S(23, 48), S(23, 48),
+    S(23, 48), S(23, 48), S(20, 48), S(13, 43) };
+
+  // Isolated pawn penalty by opposed flag and file
+  const Score Isolated[2][FILE_NB] = {
+  { S(37, 45), S(54, 52), S(60, 52), S(60, 52),
+    S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
+  { S(25, 30), S(36, 35), S(40, 35), S(40, 35),
+    S(40, 35), S(40, 35), S(36, 35), S(25, 30) } };
+
+  // Backward pawn penalty by opposed flag and file
+  const Score Backward[2][FILE_NB] = {
+  { S(30, 42), S(43, 46), S(49, 46), S(49, 46),
+    S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
+  { S(20, 28), S(29, 31), S(33, 31), S(33, 31),
+    S(33, 31), S(33, 31), S(29, 31), S(20, 28) } };
+
+  // Connected pawn bonus by file and rank (initialized by formula)
+  Score Connected[FILE_NB][RANK_NB];
+
+  // Candidate passed pawn bonus by rank
+  const Score CandidatePassed[RANK_NB] = {
+    S( 0, 0), S( 6, 13), S(6,13), S(14,29),
+    S(34,68), S(83,166), S(0, 0), S( 0, 0) };
+
+  // Levers bonus by rank
+  const Score Lever[RANK_NB] = {
+    S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
+    S(20,20), S(40,40), S(0, 0), S(0, 0) };
+
+  // Bonus for file distance of the two outermost pawns
+  const Score PawnsFileSpan = S(0, 15);
+
+  // Unsupported pawn penalty
+  const Score UnsupportedPawnPenalty = S(20, 10);
+
+  // Weakness of our pawn shelter in front of the king indexed by [rank]
+  const Value ShelterWeakness[RANK_NB] =
+  { V(100), V(0), V(27), V(73), V(92), V(101), V(101) };
+
+  // Danger of enemy pawns moving toward our king indexed by
+  // [no friendly pawn | pawn unblocked | pawn blocked][rank of enemy pawn]
+  const Value StormDanger[][RANK_NB] = {
+  { V( 0),  V(64), V(128), V(51), V(26) },
+  { V(26),  V(32), V( 96), V(38), V(20) },
+  { V( 0),  V( 0), V(160), V(25), V(13) } };
+
+  // Max bonus for king safety. Corresponds to start position with all the pawns
+  // in front of the king and no enemy pawn on the horizon.
+  const Value MaxSafetyBonus = V(263);
+
+  #undef S
+  #undef V
+
+  template<Color Us>
+  Score evaluate(const Position& pos, Pawns::Entry* e) {
+
+    const Color  Them  = (Us == WHITE ? BLACK    : WHITE);
+    const Square Up    = (Us == WHITE ? DELTA_N  : DELTA_S);
+    const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
+    const Square Left  = (Us == WHITE ? DELTA_NW : DELTA_SE);
+
+    Bitboard b, p, doubled;
+    Square s;
+    File f;
+    bool passed, isolated, opposed, connected, backward, candidate, unsupported, lever;
+    Score value = SCORE_ZERO;
+    const Square* pl = pos.list<PAWN>(Us);
+    const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
+
+    Bitboard ourPawns   = pos.pieces(Us  , PAWN);
+    Bitboard theirPawns = pos.pieces(Them, PAWN);
+
+    e->passedPawns[Us] = e->candidatePawns[Us] = 0;
+    e->kingSquares[Us] = SQ_NONE;
+    e->semiopenFiles[Us] = 0xFF;
+    e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
+    e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares);
+    e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
+
+    // Loop through all pawns of the current color and score each pawn
+    while ((s = *pl++) != SQ_NONE)
+    {
+        assert(pos.piece_on(s) == make_piece(Us, PAWN));
+
+        f = file_of(s);
+
+        // This file cannot be semi-open
+        e->semiopenFiles[Us] &= ~(1 << f);
+
+        // Previous rank
+        p = rank_bb(s - pawn_push(Us));
+
+        // Our rank plus previous one
+        b = rank_bb(s) | p;
+
+        // Flag the pawn as passed, isolated, doubled,
+        // unsupported or connected (but not the backward one).
+        connected   =   ourPawns   & adjacent_files_bb(f) & b;
+        unsupported = !(ourPawns   & adjacent_files_bb(f) & p);
+        isolated    = !(ourPawns   & adjacent_files_bb(f));
+        doubled     =   ourPawns   & forward_bb(Us, s);
+        opposed     =   theirPawns & forward_bb(Us, s);
+        passed      = !(theirPawns & passed_pawn_mask(Us, s));
+        lever       =   theirPawns & pawnAttacksBB[s];
+
+        // Test for backward pawn.
+        // If the pawn is passed, isolated, or connected it cannot be
+        // backward. If there are friendly pawns behind on adjacent files
+        // or if it can capture an enemy pawn it cannot be backward either.
+        if (   (passed | isolated | connected)
+            || (ourPawns & pawn_attack_span(Them, s))
+            || (pos.attacks_from<PAWN>(s, Us) & theirPawns))
+            backward = false;
+        else
+        {
+            // We now know that there are no friendly pawns beside or behind this
+            // pawn on adjacent files. We now check whether the pawn is
+            // backward by looking in the forward direction on the adjacent
+            // files, and picking the closest pawn there.
+            b = pawn_attack_span(Us, s) & (ourPawns | theirPawns);
+            b = pawn_attack_span(Us, s) & rank_bb(backmost_sq(Us, b));
+
+            // If we have an enemy pawn in the same or next rank, the pawn is
+            // backward because it cannot advance without being captured.
+            backward = (b | shift_bb<Up>(b)) & theirPawns;
+        }
+
+        assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns));
+
+        // A not-passed pawn is a candidate to become passed, if it is free to
+        // advance and if the number of friendly pawns beside or behind this
+        // pawn on adjacent files is higher than or equal to the number of
+        // enemy pawns in the forward direction on the adjacent files.
+        candidate =   !(opposed | passed | backward | isolated)
+                   && (b = pawn_attack_span(Them, s + pawn_push(Us)) & ourPawns) != 0
+                   &&  popcount<Max15>(b) >= popcount<Max15>(pawn_attack_span(Us, s) & theirPawns);
+
+        // Passed pawns will be properly scored in evaluation because we need
+        // full attack info to evaluate passed pawns. Only the frontmost passed
+        // pawn on each file is considered a true passed pawn.
+        if (passed && !doubled)
+            e->passedPawns[Us] |= s;
+
+        // Score this pawn
+        if (isolated)
+            value -= Isolated[opposed][f];
+
+        if (unsupported && !isolated)
+            value -= UnsupportedPawnPenalty;
+
+        if (doubled)
+            value -= Doubled[f] / rank_distance(s, lsb(doubled));
+
+        if (backward)
+            value -= Backward[opposed][f];
+
+        if (connected)
+            value += Connected[f][relative_rank(Us, s)];
+
+        if (lever)
+            value += Lever[relative_rank(Us, s)];
+
+        if (candidate)
+        {
+            value += CandidatePassed[relative_rank(Us, s)];
+
+            if (!doubled)
+                e->candidatePawns[Us] |= s;
+        }
+    }
+
+    // In endgame it's better to have pawns on both wings. So give a bonus according
+    // to file distance between left and right outermost pawns.
+    if (pos.count<PAWN>(Us) > 1)
+    {
+        b = e->semiopenFiles[Us] ^ 0xFF;
+        value += PawnsFileSpan * int(msb(b) - lsb(b));
+    }
+
+    return value;
+  }
+
+} // namespace
+
+namespace Pawns {
+
+/// init() initializes some tables by formula instead of hard-coding their values
+
+void init() {
+
+  const int bonusByFile[] = { 1, 3, 3, 4, 4, 3, 3, 1 };
+
+  for (Rank r = RANK_1; r < RANK_8; ++r)
+      for (File f = FILE_A; f <= FILE_H; ++f)
+      {
+          int bonus = r * (r - 1) * (r - 2) + bonusByFile[f] * (r / 2 + 1);
+          Connected[f][r] = make_score(bonus, bonus);
+      }
+}
+
+
+/// probe() takes a position as input, computes a Entry object, and returns a
+/// pointer to it. The result is also stored in a hash table, so we don't have
+/// to recompute everything when the same pawn structure occurs again.
+
+Entry* probe(const Position& pos, Table& entries) {
+
+  Key key = pos.pawn_key();
+  Entry* e = entries[key];
+
+  if (e->key == key)
+      return e;
+
+  e->key = key;
+  e->value = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
+  return e;
+}
+
+
+/// Entry::shelter_storm() calculates shelter and storm penalties for the file
+/// the king is on, as well as the two adjacent files.
+
+template<Color Us>
+Value Entry::shelter_storm(const Position& pos, Square ksq) {
+
+  const Color Them = (Us == WHITE ? BLACK : WHITE);
+  const Bitboard Edges = (FileABB | FileHBB) & (Rank2BB | Rank3BB);
+
+  Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq));
+  Bitboard ourPawns = b & pos.pieces(Us);
+  Bitboard theirPawns = b & pos.pieces(Them);
+  Value safety = MaxSafetyBonus;
+  File kf = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
+
+  for (File f = kf - File(1); f <= kf + File(1); ++f)
+  {
+      b = ourPawns & file_bb(f);
+      Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
+
+      b  = theirPawns & file_bb(f);
+      Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
+
+      if (   (Edges & make_square(f, rkThem))
+          && file_of(ksq) == f
+          && relative_rank(Us, ksq) == rkThem - 1)
+          safety += 200;
+      else
+          safety -=  ShelterWeakness[rkUs]
+                   + StormDanger[rkUs   == RANK_1   ? 0 :
+                                 rkThem != rkUs + 1 ? 1 : 2][rkThem];
+  }
+
+  return safety;
+}
+
+
+/// Entry::do_king_safety() calculates a bonus for king safety. It is called only
+/// when king square changes, which is about 20% of total king_safety() calls.
+
+template<Color Us>
+Score Entry::do_king_safety(const Position& pos, Square ksq) {
+
+  kingSquares[Us] = ksq;
+  castlingRights[Us] = pos.can_castle(Us);
+  minKPdistance[Us] = 0;
+
+  Bitboard pawns = pos.pieces(Us, PAWN);
+  if (pawns)
+      while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {}
+
+  if (relative_rank(Us, ksq) > RANK_4)
+      return make_score(0, -16 * minKPdistance[Us]);
+
+  Value bonus = shelter_storm<Us>(pos, ksq);
+
+  // If we can castle use the bonus after the castling if it is bigger
+  if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
+      bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));
+
+  if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
+      bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
+
+  return make_score(bonus, -16 * minKPdistance[Us]);
+}
+
+// Explicit template instantiation
+template Score Entry::do_king_safety<WHITE>(const Position& pos, Square ksq);
+template Score Entry::do_king_safety<BLACK>(const Position& pos, Square ksq);
+
+} // namespace Pawns
diff --git a/src/pawns.h b/src/pawns.h
new file mode 100644 (file)
index 0000000..28fe1c0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PAWNS_H_INCLUDED
+#define PAWNS_H_INCLUDED
+
+#include "misc.h"
+#include "position.h"
+#include "types.h"
+
+namespace Pawns {
+
+/// Pawns::Entry contains various information about a pawn structure. A lookup
+/// to the pawn hash table (performed by calling the probe function) returns a
+/// pointer to an Entry object.
+
+struct Entry {
+
+  Score pawns_value() const { return value; }
+  Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
+  Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
+  Bitboard candidate_pawns(Color c) const { return candidatePawns[c]; }
+
+  int semiopen_file(Color c, File f) const {
+    return semiopenFiles[c] & (1 << f);
+  }
+
+  int semiopen_side(Color c, File f, bool leftSide) const {
+    return semiopenFiles[c] & (leftSide ? (1 << f) - 1 : ~((1 << (f + 1)) - 1));
+  }
+
+  int pawns_on_same_color_squares(Color c, Square s) const {
+    return pawnsOnSquares[c][!!(DarkSquares & s)];
+  }
+
+  template<Color Us>
+  Score king_safety(const Position& pos, Square ksq)  {
+    return  kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us)
+          ? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos, ksq));
+  }
+
+  template<Color Us>
+  Score do_king_safety(const Position& pos, Square ksq);
+
+  template<Color Us>
+  Value shelter_storm(const Position& pos, Square ksq);
+
+  Key key;
+  Score value;
+  Bitboard passedPawns[COLOR_NB];
+  Bitboard candidatePawns[COLOR_NB];
+  Bitboard pawnAttacks[COLOR_NB];
+  Square kingSquares[COLOR_NB];
+  Score kingSafety[COLOR_NB];
+  int minKPdistance[COLOR_NB];
+  int castlingRights[COLOR_NB];
+  int semiopenFiles[COLOR_NB];
+  int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
+};
+
+typedef HashTable<Entry, 16384> Table;
+
+void init();
+Entry* probe(const Position& pos, Table& entries);
+
+} // namespace Pawns
+
+#endif // #ifndef PAWNS_H_INCLUDED
diff --git a/src/platform.h b/src/platform.h
new file mode 100644 (file)
index 0000000..151c882
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PLATFORM_H_INCLUDED
+#define PLATFORM_H_INCLUDED
+
+#ifdef _MSC_VER
+
+// Disable some silly and noisy warnings from MSVC compiler
+#pragma warning(disable: 4127) // Conditional expression is constant
+#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
+#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
+#pragma warning(disable: 4996) // Function _ftime() may be unsafe
+
+// MSVC does not support <inttypes.h>
+typedef   signed __int8    int8_t;
+typedef unsigned __int8   uint8_t;
+typedef   signed __int16  int16_t;
+typedef unsigned __int16 uint16_t;
+typedef   signed __int32  int32_t;
+typedef unsigned __int32 uint32_t;
+typedef   signed __int64  int64_t;
+typedef unsigned __int64 uint64_t;
+
+#else
+#  include <inttypes.h>
+#endif
+
+#ifndef _WIN32 // Linux - Unix
+
+#  include <sys/time.h>
+
+inline int64_t system_time_to_msec() {
+  timeval t;
+  gettimeofday(&t, NULL);
+  return t.tv_sec * 1000LL + t.tv_usec / 1000;
+}
+
+#  include <pthread.h>
+typedef pthread_mutex_t Lock;
+typedef pthread_cond_t WaitCondition;
+typedef pthread_t NativeHandle;
+typedef void*(*pt_start_fn)(void*);
+
+#  define lock_init(x) pthread_mutex_init(&(x), NULL)
+#  define lock_grab(x) pthread_mutex_lock(&(x))
+#  define lock_release(x) pthread_mutex_unlock(&(x))
+#  define lock_destroy(x) pthread_mutex_destroy(&(x))
+#  define cond_destroy(x) pthread_cond_destroy(&(x))
+#  define cond_init(x) pthread_cond_init(&(x), NULL)
+#  define cond_signal(x) pthread_cond_signal(&(x))
+#  define cond_wait(x,y) pthread_cond_wait(&(x),&(y))
+#  define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z)
+#  define thread_create(x,f,t) pthread_create(&(x),NULL,(pt_start_fn)f,t)
+#  define thread_join(x) pthread_join(x, NULL)
+
+#else // Windows and MinGW
+
+#  include <sys/timeb.h>
+
+inline int64_t system_time_to_msec() {
+  _timeb t;
+  _ftime(&t);
+  return t.time * 1000LL + t.millitm;
+}
+
+#ifndef NOMINMAX
+#  define NOMINMAX // disable macros min() and max()
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#undef NOMINMAX
+
+// We use critical sections on Windows to support Windows XP and older versions.
+// Unfortunately, cond_wait() is racy between lock_release() and WaitForSingleObject()
+// but apart from this they have the same speed performance of SRW locks.
+typedef CRITICAL_SECTION Lock;
+typedef HANDLE WaitCondition;
+typedef HANDLE NativeHandle;
+
+// On Windows 95 and 98 parameter lpThreadId may not be null
+inline DWORD* dwWin9xKludge() { static DWORD dw; return &dw; }
+
+#  define lock_init(x) InitializeCriticalSection(&(x))
+#  define lock_grab(x) EnterCriticalSection(&(x))
+#  define lock_release(x) LeaveCriticalSection(&(x))
+#  define lock_destroy(x) DeleteCriticalSection(&(x))
+#  define cond_init(x) { x = CreateEvent(0, FALSE, FALSE, 0); }
+#  define cond_destroy(x) CloseHandle(x)
+#  define cond_signal(x) SetEvent(x)
+#  define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); }
+#  define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); }
+#  define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,dwWin9xKludge()))
+#  define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); }
+
+#endif
+
+#endif // #ifndef PLATFORM_H_INCLUDED
diff --git a/src/position.cpp b/src/position.cpp
new file mode 100644 (file)
index 0000000..0724e2a
--- /dev/null
@@ -0,0 +1,1279 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+
+#include "bitcount.h"
+#include "movegen.h"
+#include "notation.h"
+#include "position.h"
+#include "psqtab.h"
+#include "rkiss.h"
+#include "thread.h"
+#include "tt.h"
+#include "notation.h"
+
+using std::string;
+
+static const string PieceToChar(" PNBRQK  pnbrqk");
+
+CACHE_LINE_ALIGNMENT
+
+Value PieceValue[PHASE_NB][PIECE_NB] = {
+{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
+{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } };
+
+static Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+
+namespace Zobrist {
+
+  Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+  Key enpassant[FILE_NB];
+  Key castling[CASTLING_RIGHT_NB];
+  Key side;
+  Key exclusion;
+}
+
+Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion;}
+
+namespace {
+
+// min_attacker() is a helper function used by see() to locate the least
+// valuable attacker for the side to move, remove the attacker we just found
+// from the bitboards and scan for new X-ray attacks behind it.
+
+template<int Pt> FORCE_INLINE
+PieceType min_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers,
+                       Bitboard& occupied, Bitboard& attackers) {
+
+  Bitboard b = stmAttackers & bb[Pt];
+  if (!b)
+      return min_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers);
+
+  occupied ^= b & ~(b - 1);
+
+  if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
+      attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]);
+
+  if (Pt == ROOK || Pt == QUEEN)
+      attackers |= attacks_bb<ROOK>(to, occupied) & (bb[ROOK] | bb[QUEEN]);
+
+  attackers &= occupied; // After X-ray that may add already processed pieces
+  return (PieceType)Pt;
+}
+
+template<> FORCE_INLINE
+PieceType min_attacker<KING>(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) {
+  return KING; // No need to update bitboards: it is the last cycle
+}
+
+} // namespace
+
+
+/// CheckInfo c'tor
+
+CheckInfo::CheckInfo(const Position& pos) {
+
+  Color them = ~pos.side_to_move();
+  ksq = pos.king_square(them);
+
+  pinned = pos.pinned_pieces(pos.side_to_move());
+  dcCandidates = pos.discovered_check_candidates();
+
+  checkSq[PAWN]   = pos.attacks_from<PAWN>(ksq, them);
+  checkSq[KNIGHT] = pos.attacks_from<KNIGHT>(ksq);
+  checkSq[BISHOP] = pos.attacks_from<BISHOP>(ksq);
+  checkSq[ROOK]   = pos.attacks_from<ROOK>(ksq);
+  checkSq[QUEEN]  = checkSq[BISHOP] | checkSq[ROOK];
+  checkSq[KING]   = 0;
+}
+
+
+/// Position::init() initializes at startup the various arrays used to compute
+/// hash keys and the piece square tables. The latter is a two-step operation:
+/// Firstly, the white halves of the tables are copied from PSQT[] tables.
+/// Secondly, the black halves of the tables are initialized by flipping and
+/// changing the sign of the white scores.
+
+void Position::init() {
+
+  RKISS rk;
+
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (PieceType pt = PAWN; pt <= KING; ++pt)
+          for (Square s = SQ_A1; s <= SQ_H8; ++s)
+              Zobrist::psq[c][pt][s] = rk.rand<Key>();
+
+  for (File f = FILE_A; f <= FILE_H; ++f)
+      Zobrist::enpassant[f] = rk.rand<Key>();
+
+  for (int cf = NO_CASTLING; cf <= ANY_CASTLING; ++cf)
+  {
+      Bitboard b = cf;
+      while (b)
+      {
+          Key k = Zobrist::castling[1ULL << pop_lsb(&b)];
+          Zobrist::castling[cf] ^= k ? k : rk.rand<Key>();
+      }
+  }
+
+  Zobrist::side = rk.rand<Key>();
+  Zobrist::exclusion  = rk.rand<Key>();
+
+  for (PieceType pt = PAWN; pt <= KING; ++pt)
+  {
+      PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
+      PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];
+
+      Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);
+
+      for (Square s = SQ_A1; s <= SQ_H8; ++s)
+      {
+         psq[WHITE][pt][ s] =  (v + PSQT[pt][s]);
+         psq[BLACK][pt][~s] = -(v + PSQT[pt][s]);
+      }
+  }
+}
+
+
+/// Position::operator=() creates a copy of 'pos'. We want the new born Position
+/// object to not depend on any external data so we detach state pointer from
+/// the source one.
+
+Position& Position::operator=(const Position& pos) {
+
+  std::memcpy(this, &pos, sizeof(Position));
+  startState = *st;
+  st = &startState;
+  nodes = 0;
+
+  assert(pos_is_ok());
+
+  return *this;
+}
+
+
+/// Position::clear() erases the position object to a pristine state, with an
+/// empty board, white to move, and no castling rights.
+
+void Position::clear() {
+
+  std::memset(this, 0, sizeof(Position));
+  startState.epSquare = SQ_NONE;
+  st = &startState;
+
+  for (int i = 0; i < PIECE_TYPE_NB; ++i)
+      for (int j = 0; j < 16; ++j)
+          pieceList[WHITE][i][j] = pieceList[BLACK][i][j] = SQ_NONE;
+}
+
+
+/// Position::set() initializes the position object with the given FEN string.
+/// This function is not very robust - make sure that input FENs are correct,
+/// this is assumed to be the responsibility of the GUI.
+
+void Position::set(const string& fenStr, bool isChess960, Thread* th) {
+/*
+   A FEN string defines a particular position using only the ASCII character set.
+
+   A FEN string contains six fields separated by a space. The fields are:
+
+   1) Piece placement (from white's perspective). Each rank is described, starting
+      with rank 8 and ending with rank 1. Within each rank, the contents of each
+      square are described from file A through file H. Following the Standard
+      Algebraic Notation (SAN), each piece is identified by a single letter taken
+      from the standard English names. White pieces are designated using upper-case
+      letters ("PNBRQK") whilst Black uses lowercase ("pnbrqk"). Blank squares are
+      noted using digits 1 through 8 (the number of blank squares), and "/"
+      separates ranks.
+
+   2) Active color. "w" means white moves next, "b" means black.
+
+   3) Castling availability. If neither side can castle, this is "-". Otherwise,
+      this has one or more letters: "K" (White can castle kingside), "Q" (White
+      can castle queenside), "k" (Black can castle kingside), and/or "q" (Black
+      can castle queenside).
+
+   4) En passant target square (in algebraic notation). If there's no en passant
+      target square, this is "-". If a pawn has just made a 2-square move, this
+      is the position "behind" the pawn. This is recorded regardless of whether
+      there is a pawn in position to make an en passant capture.
+
+   5) Halfmove clock. This is the number of halfmoves since the last pawn advance
+      or capture. This is used to determine if a draw can be claimed under the
+      fifty-move rule.
+
+   6) Fullmove number. The number of the full move. It starts at 1, and is
+      incremented after Black's move.
+*/
+
+  unsigned char col, row, token;
+  size_t idx;
+  Square sq = SQ_A8;
+  std::istringstream ss(fenStr);
+
+  clear();
+  ss >> std::noskipws;
+
+  // 1. Piece placement
+  while ((ss >> token) && !isspace(token))
+  {
+      if (isdigit(token))
+          sq += Square(token - '0'); // Advance the given number of files
+
+      else if (token == '/')
+          sq -= Square(16);
+
+      else if ((idx = PieceToChar.find(token)) != string::npos)
+      {
+          put_piece(sq, color_of(Piece(idx)), type_of(Piece(idx)));
+          ++sq;
+      }
+  }
+
+  // 2. Active color
+  ss >> token;
+  sideToMove = (token == 'w' ? WHITE : BLACK);
+  ss >> token;
+
+  // 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
+  // Shredder-FEN that uses the letters of the columns on which the rooks began
+  // the game instead of KQkq and also X-FEN standard that, in case of Chess960,
+  // if an inner rook is associated with the castling right, the castling tag is
+  // replaced by the file letter of the involved rook, as for the Shredder-FEN.
+  while ((ss >> token) && !isspace(token))
+  {
+      Square rsq;
+      Color c = islower(token) ? BLACK : WHITE;
+
+      token = char(toupper(token));
+
+      if (token == 'K')
+          for (rsq = relative_square(c, SQ_H1); type_of(piece_on(rsq)) != ROOK; --rsq) {}
+
+      else if (token == 'Q')
+          for (rsq = relative_square(c, SQ_A1); type_of(piece_on(rsq)) != ROOK; ++rsq) {}
+
+      else if (token >= 'A' && token <= 'H')
+          rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
+
+      else
+          continue;
+
+      set_castling_right(c, rsq);
+  }
+
+  // 4. En passant square. Ignore if no pawn capture is possible
+  if (   ((ss >> col) && (col >= 'a' && col <= 'h'))
+      && ((ss >> row) && (row == '3' || row == '6')))
+  {
+      st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
+
+      if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)))
+          st->epSquare = SQ_NONE;
+  }
+
+  // 5-6. Halfmove clock and fullmove number
+  ss >> std::skipws >> st->rule50 >> gamePly;
+
+  // Convert from fullmove starting from 1 to ply starting from 0,
+  // handle also common incorrect FEN with fullmove = 0.
+  gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
+
+  chess960 = isChess960;
+  thisThread = th;
+  set_state(st);
+
+  assert(pos_is_ok());
+}
+
+
+/// Position::set_castling_right() is a helper function used to set castling
+/// rights given the corresponding color and the rook starting square.
+
+void Position::set_castling_right(Color c, Square rfrom) {
+
+  Square kfrom = king_square(c);
+  CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
+  CastlingRight cr = (c | cs);
+
+  st->castlingRights |= cr;
+  castlingRightsMask[kfrom] |= cr;
+  castlingRightsMask[rfrom] |= cr;
+  castlingRookSquare[cr] = rfrom;
+
+  Square kto = relative_square(c, cs == KING_SIDE ? SQ_G1 : SQ_C1);
+  Square rto = relative_square(c, cs == KING_SIDE ? SQ_F1 : SQ_D1);
+
+  for (Square s = std::min(rfrom, rto); s <= std::max(rfrom, rto); ++s)
+      if (s != kfrom && s != rfrom)
+          castlingPath[cr] |= s;
+
+  for (Square s = std::min(kfrom, kto); s <= std::max(kfrom, kto); ++s)
+      if (s != kfrom && s != rfrom)
+          castlingPath[cr] |= s;
+}
+
+
+/// Position::set_state() computes the hash keys of the position, and other
+/// data that once computed is updated incrementally as moves are made.
+/// The function is only used when a new position is set up, and to verify
+/// the correctness of the StateInfo data when running in debug mode.
+
+void Position::set_state(StateInfo* si) const {
+
+  si->key = si->pawnKey = si->materialKey = 0;
+  si->npMaterial[WHITE] = si->npMaterial[BLACK] = VALUE_ZERO;
+  si->psq = SCORE_ZERO;
+
+  si->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
+
+  for (Bitboard b = pieces(); b; )
+  {
+      Square s = pop_lsb(&b);
+      Piece pc = piece_on(s);
+      si->key ^= Zobrist::psq[color_of(pc)][type_of(pc)][s];
+      si->psq += psq[color_of(pc)][type_of(pc)][s];
+  }
+
+  if (ep_square() != SQ_NONE)
+      si->key ^= Zobrist::enpassant[file_of(ep_square())];
+
+  if (sideToMove == BLACK)
+      si->key ^= Zobrist::side;
+
+  si->key ^= Zobrist::castling[st->castlingRights];
+
+  for (Bitboard b = pieces(PAWN); b; )
+  {
+      Square s = pop_lsb(&b);
+      si->pawnKey ^= Zobrist::psq[color_of(piece_on(s))][PAWN][s];
+  }
+
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (PieceType pt = PAWN; pt <= KING; ++pt)
+          for (int cnt = 0; cnt < pieceCount[c][pt]; ++cnt)
+              si->materialKey ^= Zobrist::psq[c][pt][cnt];
+
+  for (Color c = WHITE; c <= BLACK; ++c)
+      for (PieceType pt = KNIGHT; pt <= QUEEN; ++pt)
+          si->npMaterial[c] += pieceCount[c][pt] * PieceValue[MG][pt];
+}
+
+
+/// Position::fen() returns a FEN representation of the position. In case of
+/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
+
+const string Position::fen() const {
+
+  int emptyCnt;
+  std::ostringstream ss;
+
+  for (Rank r = RANK_8; r >= RANK_1; --r)
+  {
+      for (File f = FILE_A; f <= FILE_H; ++f)
+      {
+          for (emptyCnt = 0; f <= FILE_H && empty(make_square(f, r)); ++f)
+              ++emptyCnt;
+
+          if (emptyCnt)
+              ss << emptyCnt;
+
+          if (f <= FILE_H)
+              ss << PieceToChar[piece_on(make_square(f, r))];
+      }
+
+      if (r > RANK_1)
+          ss << '/';
+  }
+
+  ss << (sideToMove == WHITE ? " w " : " b ");
+
+  if (can_castle(WHITE_OO))
+      ss << (chess960 ? to_char(file_of(castling_rook_square(WHITE |  KING_SIDE)), false) : 'K');
+
+  if (can_castle(WHITE_OOO))
+      ss << (chess960 ? to_char(file_of(castling_rook_square(WHITE | QUEEN_SIDE)), false) : 'Q');
+
+  if (can_castle(BLACK_OO))
+      ss << (chess960 ? to_char(file_of(castling_rook_square(BLACK |  KING_SIDE)),  true) : 'k');
+
+  if (can_castle(BLACK_OOO))
+      ss << (chess960 ? to_char(file_of(castling_rook_square(BLACK | QUEEN_SIDE)),  true) : 'q');
+
+  if (!can_castle(WHITE) && !can_castle(BLACK))
+      ss << '-';
+
+  ss << (ep_square() == SQ_NONE ? " - " : " " + to_string(ep_square()) + " ")
+     << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
+
+  return ss.str();
+}
+
+
+/// Position::pretty() returns an ASCII representation of the position to be
+/// printed to the standard output together with the move's san notation.
+
+const string Position::pretty(Move m) const {
+
+  std::ostringstream ss;
+
+  if (m)
+      ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
+         << move_to_san(*const_cast<Position*>(this), m);
+
+  ss << "\n +---+---+---+---+---+---+---+---+\n";
+
+  for (Rank r = RANK_8; r >= RANK_1; --r)
+  {
+      for (File f = FILE_A; f <= FILE_H; ++f)
+          ss << " | " << PieceToChar[piece_on(make_square(f, r))];
+
+      ss << " |\n +---+---+---+---+---+---+---+---+\n";
+  }
+
+  ss << "\nFen: " << fen() << "\nKey: " << std::hex << std::uppercase
+     << std::setfill('0') << std::setw(16) << st->key << "\nCheckers: ";
+
+  for (Bitboard b = checkers(); b; )
+      ss << to_string(pop_lsb(&b)) << " ";
+
+  ss << "\nLegal moves: ";
+  for (MoveList<LEGAL> it(*this); *it; ++it)
+      ss << move_to_san(*const_cast<Position*>(this), *it) << " ";
+
+  return ss.str();
+}
+
+
+/// Position::game_phase() calculates the game phase interpolating total non-pawn
+/// material between endgame and midgame limits.
+
+Phase Position::game_phase() const {
+
+  Value npm = st->npMaterial[WHITE] + st->npMaterial[BLACK];
+
+  npm = std::max(EndgameLimit, std::min(npm, MidgameLimit));
+
+  return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
+}
+
+
+/// Position::check_blockers() returns a bitboard of all the pieces with color
+/// 'c' that are blocking check on the king with color 'kingColor'. A piece
+/// blocks a check if removing that piece from the board would result in a
+/// position where the king is in check. A check blocking piece can be either a
+/// pinned or a discovered check piece, according if its color 'c' is the same
+/// or the opposite of 'kingColor'.
+
+Bitboard Position::check_blockers(Color c, Color kingColor) const {
+
+  Bitboard b, pinners, result = 0;
+  Square ksq = king_square(kingColor);
+
+  // Pinners are sliders that give check when a pinned piece is removed
+  pinners = (  (pieces(  ROOK, QUEEN) & PseudoAttacks[ROOK  ][ksq])
+             | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq])) & pieces(~kingColor);
+
+  while (pinners)
+  {
+      b = between_bb(ksq, pop_lsb(&pinners)) & pieces();
+
+      if (!more_than_one(b))
+          result |= b & pieces(c);
+  }
+  return result;
+}
+
+
+/// Position::attackers_to() computes a bitboard of all pieces which attack a
+/// given square. Slider attacks use the occ bitboard to indicate occupancy.
+
+Bitboard Position::attackers_to(Square s, Bitboard occ) const {
+
+  return  (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
+        | (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
+        | (attacks_from<KNIGHT>(s)      & pieces(KNIGHT))
+        | (attacks_bb<ROOK>(s, occ)     & pieces(ROOK, QUEEN))
+        | (attacks_bb<BISHOP>(s, occ)   & pieces(BISHOP, QUEEN))
+        | (attacks_from<KING>(s)        & pieces(KING));
+}
+
+
+/// Position::legal() tests whether a pseudo-legal move is legal
+
+bool Position::legal(Move m, Bitboard pinned) const {
+
+  assert(is_ok(m));
+  assert(pinned == pinned_pieces(sideToMove));
+
+  Color us = sideToMove;
+  Square from = from_sq(m);
+
+  assert(color_of(moved_piece(m)) == us);
+  assert(piece_on(king_square(us)) == make_piece(us, KING));
+
+  // En passant captures are a tricky special case. Because they are rather
+  // uncommon, we do it simply by testing whether the king is attacked after
+  // the move is made.
+  if (type_of(m) == ENPASSANT)
+  {
+      Square ksq = king_square(us);
+      Square to = to_sq(m);
+      Square capsq = to - pawn_push(us);
+      Bitboard occ = (pieces() ^ from ^ capsq) | to;
+
+      assert(to == ep_square());
+      assert(moved_piece(m) == make_piece(us, PAWN));
+      assert(piece_on(capsq) == make_piece(~us, PAWN));
+      assert(piece_on(to) == NO_PIECE);
+
+      return   !(attacks_bb<  ROOK>(ksq, occ) & pieces(~us, QUEEN, ROOK))
+            && !(attacks_bb<BISHOP>(ksq, occ) & pieces(~us, QUEEN, BISHOP));
+  }
+
+  // If the moving piece is a king, check whether the destination
+  // square is attacked by the opponent. Castling moves are checked
+  // for legality during move generation.
+  if (type_of(piece_on(from)) == KING)
+      return type_of(m) == CASTLING || !(attackers_to(to_sq(m)) & pieces(~us));
+
+  // A non-king move is legal if and only if it is not pinned or it
+  // is moving along the ray towards or away from the king.
+  return   !pinned
+        || !(pinned & from)
+        ||  aligned(from, to_sq(m), king_square(us));
+}
+
+
+/// Position::pseudo_legal() takes a random move and tests whether the move is
+/// pseudo legal. It is used to validate moves from TT that can be corrupted
+/// due to SMP concurrent access or hash position key aliasing.
+
+bool Position::pseudo_legal(const Move m) const {
+
+  Color us = sideToMove;
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+  Piece pc = moved_piece(m);
+
+  // Use a slower but simpler function for uncommon cases
+  if (type_of(m) != NORMAL)
+      return MoveList<LEGAL>(*this).contains(m);
+
+  // Is not a promotion, so promotion piece must be empty
+  if (promotion_type(m) - 2 != NO_PIECE_TYPE)
+      return false;
+
+  // If the 'from' square is not occupied by a piece belonging to the side to
+  // move, the move is obviously not legal.
+  if (pc == NO_PIECE || color_of(pc) != us)
+      return false;
+
+  // The destination square cannot be occupied by a friendly piece
+  if (pieces(us) & to)
+      return false;
+
+  // Handle the special case of a pawn move
+  if (type_of(pc) == PAWN)
+  {
+      // We have already handled promotion moves, so destination
+      // cannot be on the 8th/1st rank.
+      if (rank_of(to) == relative_rank(us, RANK_8))
+          return false;
+
+      if (   !(attacks_from<PAWN>(from, us) & pieces(~us) & to) // Not a capture
+
+          && !((from + pawn_push(us) == to) && empty(to))       // Not a single push
+
+          && !(   (from + 2 * pawn_push(us) == to)              // Not a double push
+               && (rank_of(from) == relative_rank(us, RANK_2))
+               && empty(to)
+               && empty(to - pawn_push(us))))
+          return false;
+  }
+  else if (!(attacks_from(pc, from) & to))
+      return false;
+
+  // Evasions generator already takes care to avoid some kind of illegal moves
+  // and legal() relies on this. We therefore have to take care that the same
+  // kind of moves are filtered out here.
+  if (checkers())
+  {
+      if (type_of(pc) != KING)
+      {
+          // Double check? In this case a king move is required
+          if (more_than_one(checkers()))
+              return false;
+
+          // Our move must be a blocking evasion or a capture of the checking piece
+          if (!((between_bb(lsb(checkers()), king_square(us)) | checkers()) & to))
+              return false;
+      }
+      // In case of king moves under check we have to remove king so as to catch
+      // invalid moves like b1a1 when opposite queen is on c1.
+      else if (attackers_to(to, pieces() ^ from) & pieces(~us))
+          return false;
+  }
+
+  return true;
+}
+
+
+/// Position::gives_check() tests whether a pseudo-legal move gives a check
+
+bool Position::gives_check(Move m, const CheckInfo& ci) const {
+
+  assert(is_ok(m));
+  assert(ci.dcCandidates == discovered_check_candidates());
+  assert(color_of(moved_piece(m)) == sideToMove);
+
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+  PieceType pt = type_of(piece_on(from));
+
+  // Is there a direct check?
+  if (ci.checkSq[pt] & to)
+      return true;
+
+  // Is there a discovered check?
+  if (   unlikely(ci.dcCandidates)
+      && (ci.dcCandidates & from)
+      && !aligned(from, to, ci.ksq))
+      return true;
+
+  switch (type_of(m))
+  {
+  case NORMAL:
+      return false;
+
+  case PROMOTION:
+      return attacks_bb(Piece(promotion_type(m)), to, pieces() ^ from) & ci.ksq;
+
+  // En passant capture with check? We have already handled the case
+  // of direct checks and ordinary discovered check, so the only case we
+  // need to handle is the unusual case of a discovered check through
+  // the captured pawn.
+  case ENPASSANT:
+  {
+      Square capsq = make_square(file_of(to), rank_of(from));
+      Bitboard b = (pieces() ^ from ^ capsq) | to;
+
+      return  (attacks_bb<  ROOK>(ci.ksq, b) & pieces(sideToMove, QUEEN, ROOK))
+            | (attacks_bb<BISHOP>(ci.ksq, b) & pieces(sideToMove, QUEEN, BISHOP));
+  }
+  case CASTLING:
+  {
+      Square kfrom = from;
+      Square rfrom = to; // Castling is encoded as 'King captures the rook'
+      Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1);
+      Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1);
+
+      return   (PseudoAttacks[ROOK][rto] & ci.ksq)
+            && (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & ci.ksq);
+  }
+  default:
+      assert(false);
+      return false;
+  }
+}
+
+
+/// Position::do_move() makes a move, and saves all information necessary
+/// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
+/// moves should be filtered out before this function is called.
+
+void Position::do_move(Move m, StateInfo& newSt) {
+
+  CheckInfo ci(*this);
+  do_move(m, newSt, ci, gives_check(m, ci));
+}
+
+void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) {
+
+  assert(is_ok(m));
+  assert(&newSt != st);
+
+  ++nodes;
+  Key k = st->key;
+
+  // Copy some fields of the old state to our new StateInfo object except the
+  // ones which are going to be recalculated from scratch anyway and then switch
+  // our state pointer to point to the new (ready to be updated) state.
+  std::memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
+
+  newSt.previous = st;
+  st = &newSt;
+
+  // Update side to move
+  k ^= Zobrist::side;
+
+  // Increment ply counters. In particular, rule50 will be reset to zero later on
+  // in case of a capture or a pawn move.
+  ++gamePly;
+  ++st->rule50;
+  ++st->pliesFromNull;
+
+  Color us = sideToMove;
+  Color them = ~us;
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+  Piece pc = piece_on(from);
+  PieceType pt = type_of(pc);
+  PieceType captured = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
+
+  assert(color_of(pc) == us);
+  assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them || type_of(m) == CASTLING);
+  assert(captured != KING);
+
+  if (type_of(m) == CASTLING)
+  {
+      assert(pc == make_piece(us, KING));
+
+      Square rfrom, rto;
+      do_castling<true>(from, to, rfrom, rto);
+
+      captured = NO_PIECE_TYPE;
+      st->psq += psq[us][ROOK][rto] - psq[us][ROOK][rfrom];
+      k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
+  }
+
+  if (captured)
+  {
+      Square capsq = to;
+
+      // If the captured piece is a pawn, update pawn hash key, otherwise
+      // update non-pawn material.
+      if (captured == PAWN)
+      {
+          if (type_of(m) == ENPASSANT)
+          {
+              capsq += pawn_push(them);
+
+              assert(pt == PAWN);
+              assert(to == st->epSquare);
+              assert(relative_rank(us, to) == RANK_6);
+              assert(piece_on(to) == NO_PIECE);
+              assert(piece_on(capsq) == make_piece(them, PAWN));
+
+              board[capsq] = NO_PIECE;
+          }
+
+          st->pawnKey ^= Zobrist::psq[them][PAWN][capsq];
+      }
+      else
+          st->npMaterial[them] -= PieceValue[MG][captured];
+
+      // Update board and piece lists
+      remove_piece(capsq, them, captured);
+
+      // Update material hash key and prefetch access to materialTable
+      k ^= Zobrist::psq[them][captured][capsq];
+      st->materialKey ^= Zobrist::psq[them][captured][pieceCount[them][captured]];
+      prefetch((char*)thisThread->materialTable[st->materialKey]);
+
+      // Update incremental scores
+      st->psq -= psq[them][captured][capsq];
+
+      // Reset rule 50 counter
+      st->rule50 = 0;
+  }
+
+  // Update hash key
+  k ^= Zobrist::psq[us][pt][from] ^ Zobrist::psq[us][pt][to];
+
+  // Reset en passant square
+  if (st->epSquare != SQ_NONE)
+  {
+      k ^= Zobrist::enpassant[file_of(st->epSquare)];
+      st->epSquare = SQ_NONE;
+  }
+
+  // Update castling rights if needed
+  if (st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
+  {
+      int cr = castlingRightsMask[from] | castlingRightsMask[to];
+      k ^= Zobrist::castling[st->castlingRights & cr];
+      st->castlingRights &= ~cr;
+  }
+
+  // Prefetch TT access as soon as we know the new hash key
+  prefetch((char*)TT.first_entry(k));
+
+  // Move the piece. The tricky Chess960 castling is handled earlier
+  if (type_of(m) != CASTLING)
+      move_piece(from, to, us, pt);
+
+  // If the moving piece is a pawn do some special extra work
+  if (pt == PAWN)
+  {
+      // Set en-passant square if the moved pawn can be captured
+      if (   (int(to) ^ int(from)) == 16
+          && (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(them, PAWN)))
+      {
+          st->epSquare = Square((from + to) / 2);
+          k ^= Zobrist::enpassant[file_of(st->epSquare)];
+      }
+
+      else if (type_of(m) == PROMOTION)
+      {
+          PieceType promotion = promotion_type(m);
+
+          assert(relative_rank(us, to) == RANK_8);
+          assert(promotion >= KNIGHT && promotion <= QUEEN);
+
+          remove_piece(to, us, PAWN);
+          put_piece(to, us, promotion);
+
+          // Update hash keys
+          k ^= Zobrist::psq[us][PAWN][to] ^ Zobrist::psq[us][promotion][to];
+          st->pawnKey ^= Zobrist::psq[us][PAWN][to];
+          st->materialKey ^=  Zobrist::psq[us][promotion][pieceCount[us][promotion]-1]
+                            ^ Zobrist::psq[us][PAWN][pieceCount[us][PAWN]];
+
+          // Update incremental score
+          st->psq += psq[us][promotion][to] - psq[us][PAWN][to];
+
+          // Update material
+          st->npMaterial[us] += PieceValue[MG][promotion];
+      }
+
+      // Update pawn hash key and prefetch access to pawnsTable
+      st->pawnKey ^= Zobrist::psq[us][PAWN][from] ^ Zobrist::psq[us][PAWN][to];
+      prefetch((char*)thisThread->pawnsTable[st->pawnKey]);
+
+      // Reset rule 50 draw counter
+      st->rule50 = 0;
+  }
+
+  // Update incremental scores
+  st->psq += psq[us][pt][to] - psq[us][pt][from];
+
+  // Set capture piece
+  st->capturedType = captured;
+
+  // Update the key with the final value
+  st->key = k;
+
+  // Update checkers bitboard: piece must be already moved due to attacks_from()
+  st->checkersBB = 0;
+
+  if (moveIsCheck)
+  {
+      if (type_of(m) != NORMAL)
+          st->checkersBB = attackers_to(king_square(them)) & pieces(us);
+      else
+      {
+          // Direct checks
+          if (ci.checkSq[pt] & to)
+              st->checkersBB |= to;
+
+          // Discovered checks
+          if (unlikely(ci.dcCandidates) && (ci.dcCandidates & from))
+          {
+              if (pt != ROOK)
+                  st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(us, QUEEN, ROOK);
+
+              if (pt != BISHOP)
+                  st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(us, QUEEN, BISHOP);
+          }
+      }
+  }
+
+  sideToMove = ~sideToMove;
+
+  assert(pos_is_ok());
+}
+
+
+/// Position::undo_move() unmakes a move. When it returns, the position should
+/// be restored to exactly the same state as before the move was made.
+
+void Position::undo_move(Move m) {
+
+  assert(is_ok(m));
+
+  sideToMove = ~sideToMove;
+
+  Color us = sideToMove;
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+  PieceType pt = type_of(piece_on(to));
+
+  assert(empty(from) || type_of(m) == CASTLING);
+  assert(st->capturedType != KING);
+
+  if (type_of(m) == PROMOTION)
+  {
+      assert(pt == promotion_type(m));
+      assert(relative_rank(us, to) == RANK_8);
+      assert(promotion_type(m) >= KNIGHT && promotion_type(m) <= QUEEN);
+
+      remove_piece(to, us, promotion_type(m));
+      put_piece(to, us, PAWN);
+      pt = PAWN;
+  }
+
+  if (type_of(m) == CASTLING)
+  {
+      Square rfrom, rto;
+      do_castling<false>(from, to, rfrom, rto);
+  }
+  else
+  {
+      move_piece(to, from, us, pt); // Put the piece back at the source square
+
+      if (st->capturedType)
+      {
+          Square capsq = to;
+
+          if (type_of(m) == ENPASSANT)
+          {
+              capsq -= pawn_push(us);
+
+              assert(pt == PAWN);
+              assert(to == st->previous->epSquare);
+              assert(relative_rank(us, to) == RANK_6);
+              assert(piece_on(capsq) == NO_PIECE);
+          }
+
+          put_piece(capsq, ~us, st->capturedType); // Restore the captured piece
+      }
+  }
+
+  // Finally point our state pointer back to the previous state
+  st = st->previous;
+  --gamePly;
+
+  assert(pos_is_ok());
+}
+
+
+/// Position::do_castling() is a helper used to do/undo a castling move. This
+/// is a bit tricky, especially in Chess960.
+template<bool Do>
+void Position::do_castling(Square from, Square& to, Square& rfrom, Square& rto) {
+
+  bool kingSide = to > from;
+  rfrom = to; // Castling is encoded as "king captures friendly rook"
+  rto = relative_square(sideToMove, kingSide ? SQ_F1 : SQ_D1);
+  to  = relative_square(sideToMove, kingSide ? SQ_G1 : SQ_C1);
+
+  // Remove both pieces first since squares could overlap in Chess960
+  remove_piece(Do ?  from :  to, sideToMove, KING);
+  remove_piece(Do ? rfrom : rto, sideToMove, ROOK);
+  board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
+  put_piece(Do ?  to :  from, sideToMove, KING);
+  put_piece(Do ? rto : rfrom, sideToMove, ROOK);
+}
+
+
+/// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips
+/// the side to move without executing any move on the board.
+
+void Position::do_null_move(StateInfo& newSt) {
+
+  assert(!checkers());
+
+  std::memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here
+
+  newSt.previous = st;
+  st = &newSt;
+
+  if (st->epSquare != SQ_NONE)
+  {
+      st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
+      st->epSquare = SQ_NONE;
+  }
+
+  st->key ^= Zobrist::side;
+  prefetch((char*)TT.first_entry(st->key));
+
+  ++st->rule50;
+  st->pliesFromNull = 0;
+
+  sideToMove = ~sideToMove;
+
+  assert(pos_is_ok());
+}
+
+void Position::undo_null_move() {
+
+  assert(!checkers());
+
+  st = st->previous;
+  sideToMove = ~sideToMove;
+}
+
+
+/// Position::see() is a static exchange evaluator: It tries to estimate the
+/// material gain or loss resulting from a move.
+
+Value Position::see_sign(Move m) const {
+
+  assert(is_ok(m));
+
+  // Early return if SEE cannot be negative because captured piece value
+  // is not less then capturing one. Note that king moves always return
+  // here because king midgame value is set to 0.
+  if (PieceValue[MG][moved_piece(m)] <= PieceValue[MG][piece_on(to_sq(m))])
+      return VALUE_KNOWN_WIN;
+
+  return see(m);
+}
+
+Value Position::see(Move m) const {
+
+  Square from, to;
+  Bitboard occupied, attackers, stmAttackers;
+  Value swapList[32];
+  int slIndex = 1;
+  PieceType captured;
+  Color stm;
+
+  assert(is_ok(m));
+
+  from = from_sq(m);
+  to = to_sq(m);
+  swapList[0] = PieceValue[MG][piece_on(to)];
+  stm = color_of(piece_on(from));
+  occupied = pieces() ^ from;
+
+  // Castling moves are implemented as king capturing the rook so cannot be
+  // handled correctly. Simply return 0 that is always the correct value
+  // unless in the rare case the rook ends up under attack.
+  if (type_of(m) == CASTLING)
+      return VALUE_ZERO;
+
+  if (type_of(m) == ENPASSANT)
+  {
+      occupied ^= to - pawn_push(stm); // Remove the captured pawn
+      swapList[0] = PieceValue[MG][PAWN];
+  }
+
+  // Find all attackers to the destination square, with the moving piece
+  // removed, but possibly an X-ray attacker added behind it.
+  attackers = attackers_to(to, occupied) & occupied;
+
+  // If the opponent has no attackers we are finished
+  stm = ~stm;
+  stmAttackers = attackers & pieces(stm);
+  if (!stmAttackers)
+      return swapList[0];
+
+  // The destination square is defended, which makes things rather more
+  // difficult to compute. We proceed by building up a "swap list" containing
+  // the material gain or loss at each stop in a sequence of captures to the
+  // destination square, where the sides alternately capture, and always
+  // capture with the least valuable piece. After each capture, we look for
+  // new X-ray attacks from behind the capturing piece.
+  captured = type_of(piece_on(from));
+
+  do {
+      assert(slIndex < 32);
+
+      // Add the new entry to the swap list
+      swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured];
+
+      // Locate and remove the next least valuable attacker
+      captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
+
+      // Stop before processing a king capture
+      if (captured == KING)
+      {
+          if (stmAttackers == attackers)
+              ++slIndex;
+
+          break;
+      }
+
+      stm = ~stm;
+      stmAttackers = attackers & pieces(stm);
+      ++slIndex;
+
+  } while (stmAttackers);
+
+  // Having built the swap list, we negamax through it to find the best
+  // achievable score from the point of view of the side to move.
+  while (--slIndex)
+      swapList[slIndex - 1] = std::min(-swapList[slIndex], swapList[slIndex - 1]);
+
+  return swapList[0];
+}
+
+
+/// Position::is_draw() tests whether the position is drawn by material, 50 moves
+/// rule or repetition. It does not detect stalemates.
+
+bool Position::is_draw() const {
+
+  if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
+      return true;
+
+  StateInfo* stp = st;
+  for (int i = 2, e = std::min(st->rule50, st->pliesFromNull); i <= e; i += 2)
+  {
+      stp = stp->previous->previous;
+
+      if (stp->key == st->key)
+          return true; // Draw at first repetition
+  }
+
+  return false;
+}
+
+
+/// Position::flip() flips position with the white and black sides reversed. This
+/// is only useful for debugging e.g. for finding evaluation symmetry bugs.
+
+static char toggle_case(char c) {
+  return char(islower(c) ? toupper(c) : tolower(c));
+}
+
+void Position::flip() {
+
+  string f, token;
+  std::stringstream ss(fen());
+
+  for (Rank r = RANK_8; r >= RANK_1; --r) // Piece placement
+  {
+      std::getline(ss, token, r > RANK_1 ? '/' : ' ');
+      f.insert(0, token + (f.empty() ? " " : "/"));
+  }
+
+  ss >> token; // Active color
+  f += (token == "w" ? "B " : "W "); // Will be lowercased later
+
+  ss >> token; // Castling availability
+  f += token + " ";
+
+  std::transform(f.begin(), f.end(), f.begin(), toggle_case);
+
+  ss >> token; // En passant square
+  f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3"));
+
+  std::getline(ss, token); // Half and full moves
+  f += token;
+
+  set(f, is_chess960(), this_thread());
+
+  assert(pos_is_ok());
+}
+
+
+/// Position::pos_is_ok() performs some consistency checks for the position object.
+/// This is meant to be helpful when debugging.
+
+bool Position::pos_is_ok(int* step) const {
+
+  // Which parts of the position should be verified?
+  const bool all = false;
+
+  const bool testBitboards       = all || false;
+  const bool testState           = all || false;
+  const bool testKingCount       = all || false;
+  const bool testKingCapture     = all || false;
+  const bool testPieceCounts     = all || false;
+  const bool testPieceList       = all || false;
+  const bool testCastlingSquares = all || false;
+
+  if (step)
+      *step = 1;
+
+  if (   (sideToMove != WHITE && sideToMove != BLACK)
+      || piece_on(king_square(WHITE)) != W_KING
+      || piece_on(king_square(BLACK)) != B_KING
+      || (   ep_square() != SQ_NONE
+          && relative_rank(sideToMove, ep_square()) != RANK_6))
+      return false;
+
+  if (step && ++*step, testBitboards)
+  {
+      // The intersection of the white and black pieces must be empty
+      if (pieces(WHITE) & pieces(BLACK))
+          return false;
+
+      // The union of the white and black pieces must be equal to all
+      // occupied squares
+      if ((pieces(WHITE) | pieces(BLACK)) != pieces())
+          return false;
+
+      // Separate piece type bitboards must have empty intersections
+      for (PieceType p1 = PAWN; p1 <= KING; ++p1)
+          for (PieceType p2 = PAWN; p2 <= KING; ++p2)
+              if (p1 != p2 && (pieces(p1) & pieces(p2)))
+                  return false;
+  }
+
+  if (step && ++*step, testState)
+  {
+      StateInfo si;
+      set_state(&si);
+      if (   st->key != si.key
+          || st->pawnKey != si.pawnKey
+          || st->materialKey != si.materialKey
+          || st->npMaterial[WHITE] != si.npMaterial[WHITE]
+          || st->npMaterial[BLACK] != si.npMaterial[BLACK]
+          || st->psq != si.psq
+          || st->checkersBB != si.checkersBB)
+          return false;
+  }
+
+  if (step && ++*step, testKingCount)
+      if (   std::count(board, board + SQUARE_NB, W_KING) != 1
+          || std::count(board, board + SQUARE_NB, B_KING) != 1)
+          return false;
+
+  if (step && ++*step, testKingCapture)
+      if (attackers_to(king_square(~sideToMove)) & pieces(sideToMove))
+          return false;
+
+  if (step && ++*step, testPieceCounts)
+      for (Color c = WHITE; c <= BLACK; ++c)
+          for (PieceType pt = PAWN; pt <= KING; ++pt)
+              if (pieceCount[c][pt] != popcount<Full>(pieces(c, pt)))
+                  return false;
+
+  if (step && ++*step, testPieceList)
+      for (Color c = WHITE; c <= BLACK; ++c)
+          for (PieceType pt = PAWN; pt <= KING; ++pt)
+              for (int i = 0; i < pieceCount[c][pt];  ++i)
+                  if (   board[pieceList[c][pt][i]] != make_piece(c, pt)
+                      || index[pieceList[c][pt][i]] != i)
+                      return false;
+
+  if (step && ++*step, testCastlingSquares)
+      for (Color c = WHITE; c <= BLACK; ++c)
+          for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
+          {
+              if (!can_castle(c | s))
+                  continue;
+
+              if (  (castlingRightsMask[king_square(c)] & (c | s)) != (c | s)
+                  || piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
+                  || castlingRightsMask[castlingRookSquare[c | s]] != (c | s))
+                  return false;
+          }
+
+  return true;
+}
diff --git a/src/position.h b/src/position.h
new file mode 100644 (file)
index 0000000..d950411
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef POSITION_H_INCLUDED
+#define POSITION_H_INCLUDED
+
+#include <cassert>
+#include <cstddef>
+
+#include "bitboard.h"
+#include "types.h"
+
+
+/// The checkInfo struct is initialized at c'tor time and keeps info used
+/// to detect if a move gives check.
+class Position;
+struct Thread;
+
+struct CheckInfo {
+
+  explicit CheckInfo(const Position&);
+
+  Bitboard dcCandidates;
+  Bitboard pinned;
+  Bitboard checkSq[PIECE_TYPE_NB];
+  Square ksq;
+};
+
+
+/// The StateInfo struct stores information needed to restore a Position
+/// object to its previous state when we retract a move. Whenever a move
+/// is made on the board (by calling Position::do_move), a StateInfo
+/// object must be passed as a parameter.
+
+struct StateInfo {
+  Key pawnKey, materialKey;
+  Value npMaterial[COLOR_NB];
+  int castlingRights, rule50, pliesFromNull;
+  Score psq;
+  Square epSquare;
+
+  Key key;
+  Bitboard checkersBB;
+  PieceType capturedType;
+  StateInfo* previous;
+};
+
+
+/// When making a move the current StateInfo up to 'key' excluded is copied to
+/// the new one. Here we calculate the quad words (64bits) needed to be copied.
+const size_t StateCopySize64 = offsetof(StateInfo, key) / sizeof(uint64_t) + 1;
+
+
+/// The Position class stores the information regarding the board representation
+/// like pieces, side to move, hash keys, castling info, etc. The most important
+/// methods are do_move() and undo_move(), used by the search to update node info
+/// when traversing the search tree.
+
+class Position {
+public:
+  Position() {}
+  Position(const Position& pos, Thread* t) { *this = pos; thisThread = t; }
+  Position(const std::string& f, bool c960, Thread* t) { set(f, c960, t); }
+  Position& operator=(const Position&);
+  static void init();
+
+  // Text input/output
+  void set(const std::string& fenStr, bool isChess960, Thread* th);
+  const std::string fen() const;
+  const std::string pretty(Move m = MOVE_NONE) const;
+
+  // Position representation
+  Bitboard pieces() const;
+  Bitboard pieces(PieceType pt) const;
+  Bitboard pieces(PieceType pt1, PieceType pt2) const;
+  Bitboard pieces(Color c) const;
+  Bitboard pieces(Color c, PieceType pt) const;
+  Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
+  Piece piece_on(Square s) const;
+  Square king_square(Color c) const;
+  Square ep_square() const;
+  bool empty(Square s) const;
+  template<PieceType Pt> int count(Color c) const;
+  template<PieceType Pt> const Square* list(Color c) const;
+
+  // Castling
+  int can_castle(Color c) const;
+  int can_castle(CastlingRight cr) const;
+  bool castling_impeded(CastlingRight cr) const;
+  Square castling_rook_square(CastlingRight cr) const;
+
+  // Checking
+  Bitboard checkers() const;
+  Bitboard discovered_check_candidates() const;
+  Bitboard pinned_pieces(Color c) const;
+
+  // Attacks to/from a given square
+  Bitboard attackers_to(Square s) const;
+  Bitboard attackers_to(Square s, Bitboard occ) const;
+  Bitboard attacks_from(Piece pc, Square s) const;
+  template<PieceType> Bitboard attacks_from(Square s) const;
+  template<PieceType> Bitboard attacks_from(Square s, Color c) const;
+
+  // Properties of moves
+  bool legal(Move m, Bitboard pinned) const;
+  bool pseudo_legal(const Move m) const;
+  bool capture(Move m) const;
+  bool capture_or_promotion(Move m) const;
+  bool gives_check(Move m, const CheckInfo& ci) const;
+  bool advanced_pawn_push(Move m) const;
+  Piece moved_piece(Move m) const;
+  PieceType captured_piece_type() const;
+
+  // Piece specific
+  bool pawn_passed(Color c, Square s) const;
+  bool pawn_on_7th(Color c) const;
+  bool bishop_pair(Color c) const;
+  bool opposite_bishops() const;
+
+  // Doing and undoing moves
+  void do_move(Move m, StateInfo& st);
+  void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
+  void undo_move(Move m);
+  void do_null_move(StateInfo& st);
+  void undo_null_move();
+
+  // Static exchange evaluation
+  Value see(Move m) const;
+  Value see_sign(Move m) const;
+
+  // Accessing hash keys
+  Key key() const;
+  Key exclusion_key() const;
+  Key pawn_key() const;
+  Key material_key() const;
+
+  // Incremental piece-square evaluation
+  Score psq_score() const;
+  Value non_pawn_material(Color c) const;
+
+  // Other properties of the position
+  Color side_to_move() const;
+  Phase game_phase() const;
+  int game_ply() const;
+  bool is_chess960() const;
+  Thread* this_thread() const;
+  uint64_t nodes_searched() const;
+  void set_nodes_searched(uint64_t n);
+  bool is_draw() const;
+
+  // Position consistency check, for debugging
+  bool pos_is_ok(int* step = NULL) const;
+  void flip();
+
+private:
+  // Initialization helpers (used while setting up a position)
+  void clear();
+  void set_castling_right(Color c, Square rfrom);
+  void set_state(StateInfo* si) const;
+
+  // Helper functions
+  Bitboard check_blockers(Color c, Color kingColor) const;
+  void put_piece(Square s, Color c, PieceType pt);
+  void remove_piece(Square s, Color c, PieceType pt);
+  void move_piece(Square from, Square to, Color c, PieceType pt);
+  template<bool Do>
+  void do_castling(Square from, Square& to, Square& rfrom, Square& rto);
+
+  // Board and pieces
+  Piece board[SQUARE_NB];
+  Bitboard byTypeBB[PIECE_TYPE_NB];
+  Bitboard byColorBB[COLOR_NB];
+  int pieceCount[COLOR_NB][PIECE_TYPE_NB];
+  Square pieceList[COLOR_NB][PIECE_TYPE_NB][16];
+  int index[SQUARE_NB];
+
+  // Other info
+  int castlingRightsMask[SQUARE_NB];
+  Square castlingRookSquare[CASTLING_RIGHT_NB];
+  Bitboard castlingPath[CASTLING_RIGHT_NB];
+  StateInfo startState;
+  uint64_t nodes;
+  int gamePly;
+  Color sideToMove;
+  Thread* thisThread;
+  StateInfo* st;
+  bool chess960;
+};
+
+inline uint64_t Position::nodes_searched() const {
+  return nodes;
+}
+
+inline void Position::set_nodes_searched(uint64_t n) {
+  nodes = n;
+}
+
+inline Piece Position::piece_on(Square s) const {
+  return board[s];
+}
+
+inline Piece Position::moved_piece(Move m) const {
+  return board[from_sq(m)];
+}
+
+inline bool Position::empty(Square s) const {
+  return board[s] == NO_PIECE;
+}
+
+inline Color Position::side_to_move() const {
+  return sideToMove;
+}
+
+inline Bitboard Position::pieces() const {
+  return byTypeBB[ALL_PIECES];
+}
+
+inline Bitboard Position::pieces(PieceType pt) const {
+  return byTypeBB[pt];
+}
+
+inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
+  return byTypeBB[pt1] | byTypeBB[pt2];
+}
+
+inline Bitboard Position::pieces(Color c) const {
+  return byColorBB[c];
+}
+
+inline Bitboard Position::pieces(Color c, PieceType pt) const {
+  return byColorBB[c] & byTypeBB[pt];
+}
+
+inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
+  return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
+}
+
+template<PieceType Pt> inline int Position::count(Color c) const {
+  return pieceCount[c][Pt];
+}
+
+template<PieceType Pt> inline const Square* Position::list(Color c) const {
+  return pieceList[c][Pt];
+}
+
+inline Square Position::ep_square() const {
+  return st->epSquare;
+}
+
+inline Square Position::king_square(Color c) const {
+  return pieceList[c][KING][0];
+}
+
+inline int Position::can_castle(CastlingRight cr) const {
+  return st->castlingRights & cr;
+}
+
+inline int Position::can_castle(Color c) const {
+  return st->castlingRights & ((WHITE_OO | WHITE_OOO) << (2 * c));
+}
+
+inline bool Position::castling_impeded(CastlingRight cr) const {
+  return byTypeBB[ALL_PIECES] & castlingPath[cr];
+}
+
+inline Square Position::castling_rook_square(CastlingRight cr) const {
+  return castlingRookSquare[cr];
+}
+
+template<PieceType Pt>
+inline Bitboard Position::attacks_from(Square s) const {
+
+  return  Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, byTypeBB[ALL_PIECES])
+        : Pt == QUEEN  ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
+        : StepAttacksBB[Pt][s];
+}
+
+template<>
+inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
+  return StepAttacksBB[make_piece(c, PAWN)][s];
+}
+
+inline Bitboard Position::attacks_from(Piece pc, Square s) const {
+  return attacks_bb(pc, s, byTypeBB[ALL_PIECES]);
+}
+
+inline Bitboard Position::attackers_to(Square s) const {
+  return attackers_to(s, byTypeBB[ALL_PIECES]);
+}
+
+inline Bitboard Position::checkers() const {
+  return st->checkersBB;
+}
+
+inline Bitboard Position::discovered_check_candidates() const {
+  return check_blockers(sideToMove, ~sideToMove);
+}
+
+inline Bitboard Position::pinned_pieces(Color c) const {
+  return check_blockers(c, c);
+}
+
+inline bool Position::pawn_passed(Color c, Square s) const {
+  return !(pieces(~c, PAWN) & passed_pawn_mask(c, s));
+}
+
+inline bool Position::advanced_pawn_push(Move m) const {
+  return   type_of(moved_piece(m)) == PAWN
+        && relative_rank(sideToMove, from_sq(m)) > RANK_4;
+}
+
+inline Key Position::key() const {
+  return st->key;
+}
+
+inline Key Position::pawn_key() const {
+  return st->pawnKey;
+}
+
+inline Key Position::material_key() const {
+  return st->materialKey;
+}
+
+inline Score Position::psq_score() const {
+  return st->psq;
+}
+
+inline Value Position::non_pawn_material(Color c) const {
+  return st->npMaterial[c];
+}
+
+inline int Position::game_ply() const {
+  return gamePly;
+}
+
+inline bool Position::opposite_bishops() const {
+
+  return   pieceCount[WHITE][BISHOP] == 1
+        && pieceCount[BLACK][BISHOP] == 1
+        && opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]);
+}
+
+inline bool Position::bishop_pair(Color c) const {
+
+  return   pieceCount[c][BISHOP] >= 2
+        && opposite_colors(pieceList[c][BISHOP][0], pieceList[c][BISHOP][1]);
+}
+
+inline bool Position::pawn_on_7th(Color c) const {
+  return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7));
+}
+
+inline bool Position::is_chess960() const {
+  return chess960;
+}
+
+inline bool Position::capture_or_promotion(Move m) const {
+
+  assert(is_ok(m));
+  return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
+}
+
+inline bool Position::capture(Move m) const {
+
+  // Note that castling is encoded as "king captures the rook"
+  assert(is_ok(m));
+  return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
+}
+
+inline PieceType Position::captured_piece_type() const {
+  return st->capturedType;
+}
+
+inline Thread* Position::this_thread() const {
+  return thisThread;
+}
+
+inline void Position::put_piece(Square s, Color c, PieceType pt) {
+
+  board[s] = make_piece(c, pt);
+  byTypeBB[ALL_PIECES] |= s;
+  byTypeBB[pt] |= s;
+  byColorBB[c] |= s;
+  index[s] = pieceCount[c][pt]++;
+  pieceList[c][pt][index[s]] = s;
+}
+
+inline void Position::move_piece(Square from, Square to, Color c, PieceType pt) {
+
+  // index[from] is not updated and becomes stale. This works as long
+  // as index[] is accessed just by known occupied squares.
+  Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
+  byTypeBB[ALL_PIECES] ^= from_to_bb;
+  byTypeBB[pt] ^= from_to_bb;
+  byColorBB[c] ^= from_to_bb;
+  board[from] = NO_PIECE;
+  board[to] = make_piece(c, pt);
+  index[to] = index[from];
+  pieceList[c][pt][index[to]] = to;
+}
+
+inline void Position::remove_piece(Square s, Color c, PieceType pt) {
+
+  // WARNING: This is not a reversible operation. If we remove a piece in
+  // do_move() and then replace it in undo_move() we will put it at the end of
+  // the list and not in its original place, it means index[] and pieceList[]
+  // are not guaranteed to be invariant to a do_move() + undo_move() sequence.
+  byTypeBB[ALL_PIECES] ^= s;
+  byTypeBB[pt] ^= s;
+  byColorBB[c] ^= s;
+  /* board[s] = NO_PIECE; */ // Not needed, will be overwritten by capturing
+  Square lastSquare = pieceList[c][pt][--pieceCount[c][pt]];
+  index[lastSquare] = index[s];
+  pieceList[c][pt][index[lastSquare]] = lastSquare;
+  pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE;
+}
+
+#endif // #ifndef POSITION_H_INCLUDED
diff --git a/src/psqtab.h b/src/psqtab.h
new file mode 100644 (file)
index 0000000..a88d31d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PSQTAB_H_INCLUDED
+#define PSQTAB_H_INCLUDED
+
+#include "types.h"
+
+#define S(mg, eg) make_score(mg, eg)
+
+
+/// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on
+/// a given square a (middlegame, endgame) score pair is assigned. PSQT is defined
+/// for the white side and the tables are symmetric for the black side.
+
+static const Score PSQT[][SQUARE_NB] = {
+  { },
+  { // Pawn
+   S(  0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0,  0), S( 0, 0), S( 0, 0), S(  0, 0),
+   S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0,  0), S( 0, 0), S( 0, 0), S(-20, 0),
+   S(-20, 0), S( 0, 0), S(10, 0), S(20, 0), S(20, 0), S(10, 0), S( 0, 0), S(-20, 0),
+   S(-20, 0), S( 0, 0), S(20, 0), S(40, 0), S(40, 0), S(20, 0), S( 0, 0), S(-20, 0),
+   S(-20, 0), S( 0, 0), S(10, 0), S(20, 0), S(20, 0), S(10, 0), S( 0, 0), S(-20, 0),
+   S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0,  0), S( 0, 0), S( 0, 0), S(-20, 0),
+   S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0,  0), S( 0, 0), S( 0, 0), S(-20, 0),
+   S(  0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0,  0), S( 0, 0), S( 0, 0), S(  0, 0)
+  },
+  { // Knight
+   S(-144,-98), S(-109,-83), S(-85,-51), S(-73,-16), S(-73,-16), S(-85,-51), S(-109,-83), S(-144,-98),
+   S( -88,-68), S( -43,-53), S(-19,-21), S( -7, 14), S( -7, 14), S(-19,-21), S( -43,-53), S( -88,-68),
+   S( -69,-53), S( -24,-38), S(  0, -6), S( 12, 29), S( 12, 29), S(  0, -6), S( -24,-38), S( -69,-53),
+   S( -28,-42), S(  17,-27), S( 41,  5), S( 53, 40), S( 53, 40), S( 41,  5), S(  17,-27), S( -28,-42),
+   S( -30,-42), S(  15,-27), S( 39,  5), S( 51, 40), S( 51, 40), S( 39,  5), S(  15,-27), S( -30,-42),
+   S( -10,-53), S(  35,-38), S( 59, -6), S( 71, 29), S( 71, 29), S( 59, -6), S(  35,-38), S( -10,-53),
+   S( -64,-68), S( -19,-53), S(  5,-21), S( 17, 14), S( 17, 14), S(  5,-21), S( -19,-53), S( -64,-68),
+   S(-200,-98), S( -65,-83), S(-41,-51), S(-29,-16), S(-29,-16), S(-41,-51), S( -65,-83), S(-200,-98)
+  },
+  { // Bishop
+   S(-54,-65), S(-27,-42), S(-34,-44), S(-43,-26), S(-43,-26), S(-34,-44), S(-27,-42), S(-54,-65),
+   S(-29,-43), S(  8,-20), S(  1,-22), S( -8, -4), S( -8, -4), S(  1,-22), S(  8,-20), S(-29,-43),
+   S(-20,-33), S( 17,-10), S( 10,-12), S(  1,  6), S(  1,  6), S( 10,-12), S( 17,-10), S(-20,-33),
+   S(-19,-35), S( 18,-12), S( 11,-14), S(  2,  4), S(  2,  4), S( 11,-14), S( 18,-12), S(-19,-35),
+   S(-22,-35), S( 15,-12), S(  8,-14), S( -1,  4), S( -1,  4), S(  8,-14), S( 15,-12), S(-22,-35),
+   S(-28,-33), S(  9,-10), S(  2,-12), S( -7,  6), S( -7,  6), S(  2,-12), S(  9,-10), S(-28,-33),
+   S(-32,-43), S(  5,-20), S( -2,-22), S(-11, -4), S(-11, -4), S( -2,-22), S(  5,-20), S(-32,-43),
+   S(-49,-65), S(-22,-42), S(-29,-44), S(-38,-26), S(-38,-26), S(-29,-44), S(-22,-42), S(-49,-65)
+  },
+  { // Rook
+   S(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3),
+   S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
+   S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
+   S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
+   S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
+   S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
+   S(-11, 3), S(  4, 3), S(  9, 3), S(13, 3), S(13, 3), S(  9, 3), S(  4, 3), S(-11, 3),
+   S(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3)
+  },
+  { // Queen
+   S(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80),
+   S(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54),
+   S(-2,-42), S( 8,-18), S( 8, -6), S( 8,  6), S( 8,  6), S( 8, -6), S( 8,-18), S(-2,-42),
+   S(-2,-30), S( 8, -6), S( 8,  6), S( 8, 18), S( 8, 18), S( 8,  6), S( 8, -6), S(-2,-30),
+   S(-2,-30), S( 8, -6), S( 8,  6), S( 8, 18), S( 8, 18), S( 8,  6), S( 8, -6), S(-2,-30),
+   S(-2,-42), S( 8,-18), S( 8, -6), S( 8,  6), S( 8,  6), S( 8, -6), S( 8,-18), S(-2,-42),
+   S(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54),
+   S(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80)
+  },
+  { // King
+   S(298, 27), S(332, 81), S(273,108), S(225,116), S(225,116), S(273,108), S(332, 81), S(298, 27),
+   S(287, 74), S(321,128), S(262,155), S(214,163), S(214,163), S(262,155), S(321,128), S(287, 74),
+   S(224,111), S(258,165), S(199,192), S(151,200), S(151,200), S(199,192), S(258,165), S(224,111),
+   S(196,135), S(230,189), S(171,216), S(123,224), S(123,224), S(171,216), S(230,189), S(196,135),
+   S(173,135), S(207,189), S(148,216), S(100,224), S(100,224), S(148,216), S(207,189), S(173,135),
+   S(146,111), S(180,165), S(121,192), S( 73,200), S( 73,200), S(121,192), S(180,165), S(146,111),
+   S(119, 74), S(153,128), S( 94,155), S( 46,163), S( 46,163), S( 94,155), S(153,128), S(119, 74),
+   S( 98, 27), S(132, 81), S( 73,108), S( 25,116), S( 25,116), S( 73,108), S(132, 81), S( 98, 27)
+  }
+};
+
+#undef S
+
+#endif // #ifndef PSQTAB_H_INCLUDED
diff --git a/src/rkiss.h b/src/rkiss.h
new file mode 100644 (file)
index 0000000..f3468db
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  This file is based on original code by Heinz van Saanen and is
+  available under the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+*/
+
+#ifndef RKISS_H_INCLUDED
+#define RKISS_H_INCLUDED
+
+#include "types.h"
+
+/// RKISS is our pseudo random number generator (PRNG) used to compute hash keys.
+/// George Marsaglia invented the RNG-Kiss-family in the early 90's. This is a
+/// specific version that Heinz van Saanen derived from some public domain code
+/// by Bob Jenkins. Following the feature list, as tested by Heinz.
+///
+/// - Quite platform independent
+/// - Passes ALL dieharder tests! Here *nix sys-rand() e.g. fails miserably:-)
+/// - ~12 times faster than my *nix sys-rand()
+/// - ~4 times faster than SSE2-version of Mersenne twister
+/// - Average cycle length: ~2^126
+/// - 64 bit seed
+/// - Return doubles with a full 53 bit mantissa
+/// - Thread safe
+
+class RKISS {
+
+  uint64_t a, b, c, d;
+
+  uint64_t rotate_L(uint64_t x, unsigned k) const {
+    return (x << k) | (x >> (64 - k));
+  }
+
+  uint64_t rand64() {
+
+    const uint64_t e = a - rotate_L(b,  7);
+    a = b ^ rotate_L(c, 13);
+    b = c + rotate_L(d, 37);
+    c = d + e;
+    return d = e + a;
+  }
+
+public:
+  RKISS(int seed = 73) {
+
+    a = 0xF1EA5EED, b = c = d = 0xD4E12C77;
+
+    for (int i = 0; i < seed; ++i) // Scramble a few rounds
+        rand64();
+  }
+
+  template<typename T> T rand() { return T(rand64()); }
+
+  /// Special generator used to fast init magic numbers. Here the
+  /// trick is to rotate the randoms of a given quantity 's' known
+  /// to be optimal to quickly find a good magic candidate.
+  template<typename T> T magic_rand(int s) {
+    return rotate_L(rotate_L(rand<T>(), (s >> 0) & 0x3F) & rand<T>()
+                                      , (s >> 6) & 0x3F) & rand<T>();
+  }
+};
+
+#endif // #ifndef RKISS_H_INCLUDED
diff --git a/src/search.cpp b/src/search.cpp
new file mode 100644 (file)
index 0000000..991926c
--- /dev/null
@@ -0,0 +1,1658 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cfloat>
+#include <cmath>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+
+#include "evaluate.h"
+#include "movegen.h"
+#include "movepick.h"
+#include "notation.h"
+#include "rkiss.h"
+#include "search.h"
+#include "timeman.h"
+#include "thread.h"
+#include "tt.h"
+#include "ucioption.h"
+
+namespace Search {
+
+  volatile SignalsType Signals;
+  LimitsType Limits;
+  std::vector<RootMove> RootMoves;
+  Position RootPos;
+  Time::point SearchTime;
+  StateStackPtr SetupStates;
+}
+
+using std::string;
+using Eval::evaluate;
+using namespace Search;
+
+namespace {
+
+  // Different node types, used as template parameter
+  enum NodeType { Root, PV, NonPV };
+
+  // Dynamic razoring margin based on depth
+  inline Value razor_margin(Depth d) { return Value(512 + 16 * d); }
+
+  // Futility lookup tables (initialized at startup) and their access functions
+  int FutilityMoveCounts[2][32]; // [improving][depth]
+
+  inline Value futility_margin(Depth d) {
+    return Value(100 * d);
+  }
+
+  // Reduction lookup tables (initialized at startup) and their access function
+  int8_t Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber]
+
+  template <bool PvNode> inline Depth reduction(bool i, Depth d, int mn) {
+
+    return (Depth) Reductions[PvNode][i][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)];
+  }
+
+  size_t PVIdx;
+  TimeManager TimeMgr;
+  double BestMoveChanges;
+  Value DrawValue[COLOR_NB];
+  HistoryStats History;
+  GainsStats Gains;
+  MovesStats Countermoves, Followupmoves;
+
+  template <NodeType NT, bool SpNode>
+  Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
+
+  template <NodeType NT, bool InCheck>
+  Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
+
+  void id_loop(Position& pos);
+  Value value_to_tt(Value v, int ply);
+  Value value_from_tt(Value v, int ply);
+  void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt);
+  string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
+
+  struct Skill {
+    Skill(int l, size_t rootSize) : level(l),
+                                    candidates(l < 20 ? std::min(4, (int)rootSize) : 0),
+                                    best(MOVE_NONE) {}
+   ~Skill() {
+      if (candidates) // Swap best PV line with the sub-optimal one
+          std::swap(RootMoves[0], *std::find(RootMoves.begin(),
+                    RootMoves.end(), best ? best : pick_move()));
+    }
+
+    size_t candidates_size() const { return candidates; }
+    bool time_to_pick(int depth) const { return depth == 1 + level; }
+    Move pick_move();
+
+    int level;
+    size_t candidates;
+    Move best;
+  };
+
+} // namespace
+
+
+/// Search::init() is called during startup to initialize various lookup tables
+
+void Search::init() {
+
+  int d;  // depth (ONE_PLY == 2)
+  int hd; // half depth (ONE_PLY == 1)
+  int mc; // moveCount
+
+  // Init reductions array
+  for (hd = 1; hd < 64; ++hd) for (mc = 1; mc < 64; ++mc)
+  {
+      double    pvRed = 0.00 + log(double(hd)) * log(double(mc)) / 3.00;
+      double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25;
+      Reductions[1][1][hd][mc] = int8_t(   pvRed >= 1.0 ?    pvRed * int(ONE_PLY) : 0);
+      Reductions[0][1][hd][mc] = int8_t(nonPVRed >= 1.0 ? nonPVRed * int(ONE_PLY) : 0);
+
+      Reductions[1][0][hd][mc] = Reductions[1][1][hd][mc];
+      Reductions[0][0][hd][mc] = Reductions[0][1][hd][mc];
+
+      if (Reductions[0][0][hd][mc] > 2 * ONE_PLY)
+          Reductions[0][0][hd][mc] += ONE_PLY;
+
+      else if (Reductions[0][0][hd][mc] > 1 * ONE_PLY)
+          Reductions[0][0][hd][mc] += ONE_PLY / 2;
+  }
+
+  // Init futility move count array
+  for (d = 0; d < 32; ++d)
+  {
+      FutilityMoveCounts[0][d] = int(2.4 + 0.222 * pow(d + 0.00, 1.8));
+      FutilityMoveCounts[1][d] = int(3.0 + 0.300 * pow(d + 0.98, 1.8));
+  }
+}
+
+
+/// Search::perft() is our utility to verify move generation. All the leaf nodes
+/// up to the given depth are generated and counted and the sum returned.
+template<bool Root>
+uint64_t Search::perft(Position& pos, Depth depth) {
+
+  StateInfo st;
+  uint64_t cnt, nodes = 0;
+  CheckInfo ci(pos);
+  const bool leaf = depth == 2 * ONE_PLY;
+
+  for (MoveList<LEGAL> it(pos); *it; ++it)
+  {
+      if (Root && depth <= ONE_PLY)
+          cnt = 1, nodes++;
+      else
+      {
+          pos.do_move(*it, st, ci, pos.gives_check(*it, ci));
+          cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY);
+          nodes += cnt;
+          pos.undo_move(*it);
+      }
+      if (Root)
+          sync_cout << move_to_uci(*it, pos.is_chess960()) << ": " << cnt << sync_endl;
+  }
+  return nodes;
+}
+
+template uint64_t Search::perft<true>(Position& pos, Depth depth);
+
+
+/// Search::think() is the external interface to Stockfish's search, and is
+/// called by the main thread when the program receives the UCI 'go' command. It
+/// searches from RootPos and at the end prints the "bestmove" to output.
+
+void Search::think() {
+
+  TimeMgr.init(Limits, RootPos.game_ply(), RootPos.side_to_move());
+
+  int cf = Options["Contempt Factor"] * PawnValueEg / 100; // From centipawns
+  DrawValue[ RootPos.side_to_move()] = VALUE_DRAW - Value(cf);
+  DrawValue[~RootPos.side_to_move()] = VALUE_DRAW + Value(cf);
+
+  if (RootMoves.empty())
+  {
+      RootMoves.push_back(MOVE_NONE);
+      sync_cout << "info depth 0 score "
+                << score_to_uci(RootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
+                << sync_endl;
+
+      goto finalize;
+  }
+
+  if (Options["Write Search Log"])
+  {
+      Log log(Options["Search Log Filename"]);
+      log << "\nSearching: "  << RootPos.fen()
+          << "\ninfinite: "   << Limits.infinite
+          << " ponder: "      << Limits.ponder
+          << " time: "        << Limits.time[RootPos.side_to_move()]
+          << " increment: "   << Limits.inc[RootPos.side_to_move()]
+          << " moves to go: " << Limits.movestogo
+          << "\n" << std::endl;
+  }
+
+  // Reset the threads, still sleeping: will wake up at split time
+  for (size_t i = 0; i < Threads.size(); ++i)
+      Threads[i]->maxPly = 0;
+
+  Threads.timer->run = true;
+  Threads.timer->notify_one(); // Wake up the recurring timer
+
+  id_loop(RootPos); // Let's start searching !
+
+  Threads.timer->run = false; // Stop the timer
+
+  if (Options["Write Search Log"])
+  {
+      Time::point elapsed = Time::now() - SearchTime + 1;
+
+      Log log(Options["Search Log Filename"]);
+      log << "Nodes: "          << RootPos.nodes_searched()
+          << "\nNodes/second: " << RootPos.nodes_searched() * 1000 / elapsed
+          << "\nBest move: "    << move_to_san(RootPos, RootMoves[0].pv[0]);
+
+      StateInfo st;
+      RootPos.do_move(RootMoves[0].pv[0], st);
+      log << "\nPonder move: " << move_to_san(RootPos, RootMoves[0].pv[1]) << std::endl;
+      RootPos.undo_move(RootMoves[0].pv[0]);
+  }
+
+finalize:
+
+  // When search is stopped this info is not printed
+  sync_cout << "info nodes " << RootPos.nodes_searched()
+            << " time " << Time::now() - SearchTime + 1 << sync_endl;
+
+  // When we reach the maximum depth, we can arrive here without a raise of
+  // Signals.stop. However, if we are pondering or in an infinite search,
+  // the UCI protocol states that we shouldn't print the best move before the
+  // GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
+  // until the GUI sends one of those commands (which also raises Signals.stop).
+  if (!Signals.stop && (Limits.ponder || Limits.infinite))
+  {
+      Signals.stopOnPonderhit = true;
+      RootPos.this_thread()->wait_for(Signals.stop);
+  }
+
+  // Best move could be MOVE_NONE when searching on a stalemate position
+  sync_cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], RootPos.is_chess960())
+            << " ponder "  << move_to_uci(RootMoves[0].pv[1], RootPos.is_chess960())
+            << sync_endl;
+}
+
+
+namespace {
+
+  // id_loop() is the main iterative deepening loop. It calls search() repeatedly
+  // with increasing depth until the allocated thinking time has been consumed,
+  // user stops the search, or the maximum search depth is reached.
+
+  void id_loop(Position& pos) {
+
+    Stack stack[MAX_PLY_PLUS_6], *ss = stack+2; // To allow referencing (ss-2)
+    int depth;
+    Value bestValue, alpha, beta, delta;
+
+    std::memset(ss-2, 0, 5 * sizeof(Stack));
+
+    depth = 0;
+    BestMoveChanges = 0;
+    bestValue = delta = alpha = -VALUE_INFINITE;
+    beta = VALUE_INFINITE;
+
+    TT.new_search();
+    History.clear();
+    Gains.clear();
+    Countermoves.clear();
+    Followupmoves.clear();
+
+    size_t multiPV = Options["MultiPV"];
+    Skill skill(Options["Skill Level"], RootMoves.size());
+
+    // Do we have to play with skill handicap? In this case enable MultiPV search
+    // that we will use behind the scenes to retrieve a set of possible moves.
+    multiPV = std::max(multiPV, skill.candidates_size());
+
+    // Iterative deepening loop until requested to stop or target depth reached
+    while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
+    {
+        // Age out PV variability metric
+        BestMoveChanges *= 0.5;
+
+        // Save the last iteration's scores before first PV line is searched and
+        // all the move scores except the (new) PV are set to -VALUE_INFINITE.
+        for (size_t i = 0; i < RootMoves.size(); ++i)
+            RootMoves[i].prevScore = RootMoves[i].score;
+
+        // MultiPV loop. We perform a full root search for each PV line
+        for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx)
+        {
+            // Reset aspiration window starting size
+            if (depth >= 5)
+            {
+                delta = Value(16);
+                alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
+                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
+            }
+
+            // Start with a small aspiration window and, in the case of a fail
+            // high/low, re-search with a bigger window until we're not failing
+            // high/low anymore.
+            while (true)
+            {
+                bestValue = search<Root, false>(pos, ss, alpha, beta, depth * ONE_PLY, false);
+
+                // Bring the best move to the front. It is critical that sorting
+                // is done with a stable algorithm because all the values but the
+                // first and eventually the new best one are set to -VALUE_INFINITE
+                // and we want to keep the same order for all the moves except the
+                // new PV that goes to the front. Note that in case of MultiPV
+                // search the already searched PV lines are preserved.
+                std::stable_sort(RootMoves.begin() + PVIdx, RootMoves.end());
+
+                // Write PV back to transposition table in case the relevant
+                // entries have been overwritten during the search.
+                for (size_t i = 0; i <= PVIdx; ++i)
+                    RootMoves[i].insert_pv_in_tt(pos);
+
+                // If search has been stopped break immediately. Sorting and
+                // writing PV back to TT is safe because RootMoves is still
+                // valid, although it refers to previous iteration.
+                if (Signals.stop)
+                    break;
+
+                // When failing high/low give some update (without cluttering
+                // the UI) before a re-search.
+                if (  (bestValue <= alpha || bestValue >= beta)
+                    && Time::now() - SearchTime > 3000)
+                    sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
+
+                // In case of failing low/high increase aspiration window and
+                // re-search, otherwise exit the loop.
+                if (bestValue <= alpha)
+                {
+                    alpha = std::max(bestValue - delta, -VALUE_INFINITE);
+
+                    Signals.failedLowAtRoot = true;
+                    Signals.stopOnPonderhit = false;
+                }
+                else if (bestValue >= beta)
+                    beta = std::min(bestValue + delta, VALUE_INFINITE);
+
+                else
+                    break;
+
+                delta += 3 * delta / 8;
+
+                assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
+            }
+
+            // Sort the PV lines searched so far and update the GUI
+            std::stable_sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1);
+
+            if (PVIdx + 1 == std::min(multiPV, RootMoves.size()) || Time::now() - SearchTime > 3000)
+                sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
+        }
+
+        // If skill levels are enabled and time is up, pick a sub-optimal best move
+        if (skill.candidates_size() && skill.time_to_pick(depth))
+            skill.pick_move();
+
+        if (Options["Write Search Log"])
+        {
+            RootMove& rm = RootMoves[0];
+            if (skill.best != MOVE_NONE)
+                rm = *std::find(RootMoves.begin(), RootMoves.end(), skill.best);
+
+            Log log(Options["Search Log Filename"]);
+            log << pretty_pv(pos, depth, rm.score, Time::now() - SearchTime, &rm.pv[0])
+                << std::endl;
+        }
+
+        // Have we found a "mate in x"?
+        if (   Limits.mate
+            && bestValue >= VALUE_MATE_IN_MAX_PLY
+            && VALUE_MATE - bestValue <= 2 * Limits.mate)
+            Signals.stop = true;
+
+        // Do we have time for the next iteration? Can we stop searching now?
+        if (Limits.use_time_management() && !Signals.stop && !Signals.stopOnPonderhit)
+        {
+            // Take some extra time if the best move has changed
+            if (depth > 4 && multiPV == 1)
+                TimeMgr.pv_instability(BestMoveChanges);
+
+            // Stop the search if only one legal move is available or all
+            // of the available time has been used.
+            if (   RootMoves.size() == 1
+                || Time::now() - SearchTime > TimeMgr.available_time())
+            {
+                // If we are allowed to ponder do not stop the search now but
+                // keep pondering until the GUI sends "ponderhit" or "stop".
+                if (Limits.ponder)
+                    Signals.stopOnPonderhit = true;
+                else
+                    Signals.stop = true;
+            }
+        }
+    }
+  }
+
+
+  // search<>() is the main search function for both PV and non-PV nodes and for
+  // normal and SplitPoint nodes. When called just after a split point the search
+  // is simpler because we have already probed the hash table, done a null move
+  // search, and searched the first move before splitting, so we don't have to
+  // repeat all this work again. We also don't need to store anything to the hash
+  // table here: This is taken care of after we return from the split point.
+
+  template <NodeType NT, bool SpNode>
+  Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) {
+
+    const bool RootNode = NT == Root;
+    const bool PvNode   = NT == PV || NT == Root;
+
+    assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
+    assert(PvNode || (alpha == beta - 1));
+    assert(depth > DEPTH_ZERO);
+
+    Move quietsSearched[64];
+    StateInfo st;
+    const TTEntry *tte;
+    SplitPoint* splitPoint;
+    Key posKey;
+    Move ttMove, move, excludedMove, bestMove;
+    Depth ext, newDepth, predictedDepth;
+    Value bestValue, value, ttValue, eval, nullValue, futilityValue;
+    bool inCheck, givesCheck, pvMove, singularExtensionNode, improving;
+    bool captureOrPromotion, dangerous, doFullDepthSearch;
+    int moveCount, quietCount;
+
+    // Step 1. Initialize node
+    Thread* thisThread = pos.this_thread();
+    inCheck = pos.checkers();
+
+    if (SpNode)
+    {
+        splitPoint = ss->splitPoint;
+        bestMove   = splitPoint->bestMove;
+        bestValue  = splitPoint->bestValue;
+        tte = NULL;
+        ttMove = excludedMove = MOVE_NONE;
+        ttValue = VALUE_NONE;
+
+        assert(splitPoint->bestValue > -VALUE_INFINITE && splitPoint->moveCount > 0);
+
+        goto moves_loop;
+    }
+
+    moveCount = quietCount = 0;
+    bestValue = -VALUE_INFINITE;
+    ss->currentMove = ss->ttMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
+    ss->ply = (ss-1)->ply + 1;
+    (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
+    (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
+
+    // Used to send selDepth info to GUI
+    if (PvNode && thisThread->maxPly < ss->ply)
+        thisThread->maxPly = ss->ply;
+
+    if (!RootNode)
+    {
+        // Step 2. Check for aborted search and immediate draw
+        if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY)
+            return ss->ply > MAX_PLY && !inCheck ? evaluate(pos) : DrawValue[pos.side_to_move()];
+
+        // Step 3. Mate distance pruning. Even if we mate at the next move our score
+        // would be at best mate_in(ss->ply+1), but if alpha is already bigger because
+        // a shorter mate was found upward in the tree then there is no need to search
+        // because we will never beat the current alpha. Same logic but with reversed
+        // signs applies also in the opposite condition of being mated instead of giving
+        // mate. In this case return a fail-high score.
+        alpha = std::max(mated_in(ss->ply), alpha);
+        beta = std::min(mate_in(ss->ply+1), beta);
+        if (alpha >= beta)
+            return alpha;
+    }
+
+    // Step 4. Transposition table lookup
+    // We don't want the score of a partial search to overwrite a previous full search
+    // TT value, so we use a different position key in case of an excluded move.
+    excludedMove = ss->excludedMove;
+    posKey = excludedMove ? pos.exclusion_key() : pos.key();
+    tte = TT.probe(posKey);
+    ss->ttMove = ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE;
+    ttValue = tte ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
+
+    // At PV nodes we check for exact scores, whilst at non-PV nodes we check for
+    // a fail high/low. The biggest advantage to probing at PV nodes is to have a
+    // smooth experience in analysis mode. We don't probe at Root nodes otherwise
+    // we should also update RootMoveList to avoid bogus output.
+    if (   !RootNode
+        && tte
+        && tte->depth() >= depth
+        && ttValue != VALUE_NONE // Only in case of TT access race
+        && (           PvNode ?  tte->bound() == BOUND_EXACT
+            : ttValue >= beta ? (tte->bound() &  BOUND_LOWER)
+                              : (tte->bound() &  BOUND_UPPER)))
+    {
+        ss->currentMove = ttMove; // Can be MOVE_NONE
+
+        // If ttMove is quiet, update killers, history, counter move and followup move on TT hit
+        if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck)
+            update_stats(pos, ss, ttMove, depth, NULL, 0);
+
+        return ttValue;
+    }
+
+    // Step 5. Evaluate the position statically and update parent's gain statistics
+    if (inCheck)
+    {
+        ss->staticEval = eval = VALUE_NONE;
+        goto moves_loop;
+    }
+
+    else if (tte)
+    {
+        // Never assume anything on values stored in TT
+        if ((ss->staticEval = eval = tte->eval_value()) == VALUE_NONE)
+            eval = ss->staticEval = evaluate(pos);
+
+        // Can ttValue be used as a better position evaluation?
+        if (ttValue != VALUE_NONE)
+            if (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))
+                eval = ttValue;
+    }
+    else
+    {
+        eval = ss->staticEval =
+        (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Eval::Tempo;
+
+        TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval);
+    }
+
+    if (   !pos.captured_piece_type()
+        &&  ss->staticEval != VALUE_NONE
+        && (ss-1)->staticEval != VALUE_NONE
+        && (move = (ss-1)->currentMove) != MOVE_NULL
+        &&  move != MOVE_NONE
+        &&  type_of(move) == NORMAL)
+    {
+        Square to = to_sq(move);
+        Gains.update(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval);
+    }
+
+    // Step 6. Razoring (skipped when in check)
+    if (   !PvNode
+        &&  depth < 4 * ONE_PLY
+        &&  eval + razor_margin(depth) <= alpha
+        &&  ttMove == MOVE_NONE
+        && !pos.pawn_on_7th(pos.side_to_move()))
+    {
+        if (   depth <= ONE_PLY
+            && eval + razor_margin(3 * ONE_PLY) <= alpha)
+            return qsearch<NonPV, false>(pos, ss, alpha, beta, DEPTH_ZERO);
+
+        Value ralpha = alpha - razor_margin(depth);
+        Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1, DEPTH_ZERO);
+        if (v <= ralpha)
+            return v;
+    }
+
+    // Step 7. Futility pruning: child node (skipped when in check)
+    if (   !PvNode
+        && !ss->skipNullMove
+        &&  depth < 7 * ONE_PLY
+        &&  eval - futility_margin(depth) >= beta
+        &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
+        &&  abs(eval) < VALUE_KNOWN_WIN
+        &&  pos.non_pawn_material(pos.side_to_move()))
+        return eval - futility_margin(depth);
+
+    // Step 8. Null move search with verification search (is omitted in PV nodes)
+    if (   !PvNode
+        && !ss->skipNullMove
+        &&  depth >= 2 * ONE_PLY
+        &&  eval >= beta
+        &&  pos.non_pawn_material(pos.side_to_move()))
+    {
+        ss->currentMove = MOVE_NULL;
+
+        assert(eval - beta >= 0);
+
+        // Null move dynamic reduction based on depth and value
+        Depth R =  3 * ONE_PLY
+                 + depth / 4
+                 + (abs(beta) < VALUE_KNOWN_WIN ? int(eval - beta) / PawnValueMg * ONE_PLY
+                                                : DEPTH_ZERO);
+
+        pos.do_null_move(st);
+        (ss+1)->skipNullMove = true;
+        nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO)
+                                      : - search<NonPV, false>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode);
+        (ss+1)->skipNullMove = false;
+        pos.undo_null_move();
+
+        if (nullValue >= beta)
+        {
+            // Do not return unproven mate scores
+            if (nullValue >= VALUE_MATE_IN_MAX_PLY)
+                nullValue = beta;
+
+            if (depth < 12 * ONE_PLY && abs(beta) < VALUE_KNOWN_WIN)
+                return nullValue;
+
+            // Do verification search at high depths
+            ss->skipNullMove = true;
+            Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta, DEPTH_ZERO)
+                                        :  search<NonPV, false>(pos, ss, beta-1, beta, depth-R, false);
+            ss->skipNullMove = false;
+
+            if (v >= beta)
+                return nullValue;
+        }
+    }
+
+    // Step 9. ProbCut (skipped when in check)
+    // If we have a very good capture (i.e. SEE > seeValues[captured_piece_type])
+    // and a reduced search returns a value much above beta, we can (almost) safely
+    // prune the previous move.
+    if (   !PvNode
+        &&  depth >= 5 * ONE_PLY
+        && !ss->skipNullMove
+        &&  abs(beta) < VALUE_MATE_IN_MAX_PLY)
+    {
+        Value rbeta = std::min(beta + 200, VALUE_INFINITE);
+        Depth rdepth = depth - 4 * ONE_PLY;
+
+        assert(rdepth >= ONE_PLY);
+        assert((ss-1)->currentMove != MOVE_NONE);
+        assert((ss-1)->currentMove != MOVE_NULL);
+
+        MovePicker mp(pos, ttMove, History, pos.captured_piece_type());
+        CheckInfo ci(pos);
+
+        while ((move = mp.next_move<false>()) != MOVE_NONE)
+            if (pos.legal(move, ci.pinned))
+            {
+                ss->currentMove = move;
+                pos.do_move(move, st, ci, pos.gives_check(move, ci));
+                value = -search<NonPV, false>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
+                pos.undo_move(move);
+                if (value >= rbeta)
+                    return value;
+            }
+    }
+
+    // Step 10. Internal iterative deepening (skipped when in check)
+    if (    depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY)
+        && !ttMove
+        && (PvNode || ss->staticEval + 256 >= beta))
+    {
+        Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
+
+        ss->skipNullMove = true;
+        search<PvNode ? PV : NonPV, false>(pos, ss, alpha, beta, d, true);
+        ss->skipNullMove = false;
+
+        tte = TT.probe(posKey);
+        ttMove = tte ? tte->move() : MOVE_NONE;
+    }
+
+moves_loop: // When in check and at SpNode search starts from here
+
+    Square prevMoveSq = to_sq((ss-1)->currentMove);
+    Move countermoves[] = { Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].first,
+                            Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].second };
+
+    Square prevOwnMoveSq = to_sq((ss-2)->currentMove);
+    Move followupmoves[] = { Followupmoves[pos.piece_on(prevOwnMoveSq)][prevOwnMoveSq].first,
+                             Followupmoves[pos.piece_on(prevOwnMoveSq)][prevOwnMoveSq].second };
+
+    MovePicker mp(pos, ttMove, depth, History, countermoves, followupmoves, ss);
+    CheckInfo ci(pos);
+    value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
+    improving =   ss->staticEval >= (ss-2)->staticEval
+               || ss->staticEval == VALUE_NONE
+               ||(ss-2)->staticEval == VALUE_NONE;
+
+    singularExtensionNode =   !RootNode
+                           && !SpNode
+                           &&  depth >= 8 * ONE_PLY
+                           &&  abs(beta) < VALUE_KNOWN_WIN
+                           &&  ttMove != MOVE_NONE
+                       /*  &&  ttValue != VALUE_NONE Already implicit in the next condition */
+                           &&  abs(ttValue) < VALUE_KNOWN_WIN
+                           && !excludedMove // Recursive singular search is not allowed
+                           && (tte->bound() & BOUND_LOWER)
+                           &&  tte->depth() >= depth - 3 * ONE_PLY;
+
+    // Step 11. Loop through moves
+    // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
+    while ((move = mp.next_move<SpNode>()) != MOVE_NONE)
+    {
+      assert(is_ok(move));
+
+      if (move == excludedMove)
+          continue;
+
+      // At root obey the "searchmoves" option and skip moves not listed in Root
+      // Move List. As a consequence any illegal move is also skipped. In MultiPV
+      // mode we also skip PV moves which have been already searched.
+      if (RootNode && !std::count(RootMoves.begin() + PVIdx, RootMoves.end(), move))
+          continue;
+
+      if (SpNode)
+      {
+          // Shared counter cannot be decremented later if the move turns out to be illegal
+          if (!pos.legal(move, ci.pinned))
+              continue;
+
+          moveCount = ++splitPoint->moveCount;
+          splitPoint->mutex.unlock();
+      }
+      else
+          ++moveCount;
+
+      if (RootNode)
+      {
+          Signals.firstRootMove = (moveCount == 1);
+
+          if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
+              sync_cout << "info depth " << depth / ONE_PLY
+                        << " currmove " << move_to_uci(move, pos.is_chess960())
+                        << " currmovenumber " << moveCount + PVIdx << sync_endl;
+      }
+
+      ext = DEPTH_ZERO;
+      captureOrPromotion = pos.capture_or_promotion(move);
+
+      givesCheck =  type_of(move) == NORMAL && !ci.dcCandidates
+                  ? ci.checkSq[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
+                  : pos.gives_check(move, ci);
+
+      dangerous =   givesCheck
+                 || type_of(move) != NORMAL
+                 || pos.advanced_pawn_push(move);
+
+      // Step 12. Extend checks
+      if (givesCheck && pos.see_sign(move) >= VALUE_ZERO)
+          ext = ONE_PLY;
+
+      // Singular extension search. If all moves but one fail low on a search of
+      // (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move
+      // is singular and should be extended. To verify this we do a reduced search
+      // on all the other moves but the ttMove and if the result is lower than
+      // ttValue minus a margin then we extend the ttMove.
+      if (    singularExtensionNode
+          &&  move == ttMove
+          && !ext
+          &&  pos.legal(move, ci.pinned))
+      {
+          Value rBeta = ttValue - int(depth);
+          ss->excludedMove = move;
+          ss->skipNullMove = true;
+          value = search<NonPV, false>(pos, ss, rBeta - 1, rBeta, depth / 2, cutNode);
+          ss->skipNullMove = false;
+          ss->excludedMove = MOVE_NONE;
+
+          if (value < rBeta)
+              ext = ONE_PLY;
+      }
+
+      // Update the current move (this must be done after singular extension search)
+      newDepth = depth - ONE_PLY + ext;
+
+      // Step 13. Pruning at shallow depth (exclude PV nodes)
+      if (   !PvNode
+          && !captureOrPromotion
+          && !inCheck
+          && !dangerous
+       /* &&  move != ttMove Already implicit in the next condition */
+          &&  bestValue > VALUE_MATED_IN_MAX_PLY)
+      {
+          // Move count based pruning
+          if (   depth < 16 * ONE_PLY
+              && moveCount >= FutilityMoveCounts[improving][depth] )
+          {
+              if (SpNode)
+                  splitPoint->mutex.lock();
+
+              continue;
+          }
+
+          predictedDepth = newDepth - reduction<PvNode>(improving, depth, moveCount);
+
+          // Futility pruning: parent node
+          if (predictedDepth < 7 * ONE_PLY)
+          {
+              futilityValue = ss->staticEval + futility_margin(predictedDepth)
+                            + 128 + Gains[pos.moved_piece(move)][to_sq(move)];
+
+              if (futilityValue <= alpha)
+              {
+                  bestValue = std::max(bestValue, futilityValue);
+
+                  if (SpNode)
+                  {
+                      splitPoint->mutex.lock();
+                      if (bestValue > splitPoint->bestValue)
+                          splitPoint->bestValue = bestValue;
+                  }
+                  continue;
+              }
+          }
+
+          // Prune moves with negative SEE at low depths
+          if (predictedDepth < 4 * ONE_PLY && pos.see_sign(move) < VALUE_ZERO)
+          {
+              if (SpNode)
+                  splitPoint->mutex.lock();
+
+              continue;
+          }
+      }
+
+      // Check for legality just before making the move
+      if (!RootNode && !SpNode && !pos.legal(move, ci.pinned))
+      {
+          moveCount--;
+          continue;
+      }
+
+      pvMove = PvNode && moveCount == 1;
+      ss->currentMove = move;
+      if (!SpNode && !captureOrPromotion && quietCount < 64)
+          quietsSearched[quietCount++] = move;
+
+      // Step 14. Make the move
+      pos.do_move(move, st, ci, givesCheck);
+
+      // Step 15. Reduced depth search (LMR). If the move fails high it will be
+      // re-searched at full depth.
+      if (    depth >= 3 * ONE_PLY
+          && !pvMove
+          && !captureOrPromotion
+          &&  move != ttMove
+          &&  move != ss->killers[0]
+          &&  move != ss->killers[1])
+      {
+          ss->reduction = reduction<PvNode>(improving, depth, moveCount);
+
+          if (!PvNode && cutNode)
+              ss->reduction += ONE_PLY;
+
+          else if (History[pos.piece_on(to_sq(move))][to_sq(move)] < 0)
+              ss->reduction += ONE_PLY / 2;
+
+          if (move == countermoves[0] || move == countermoves[1])
+              ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
+
+          // Decrease reduction for moves that escape a capture
+          if (   ss->reduction
+              && type_of(move) == NORMAL
+              && type_of(pos.piece_on(to_sq(move))) != PAWN
+              && pos.see(make_move(to_sq(move), from_sq(move))) < 0)
+              ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
+
+          Depth d = std::max(newDepth - ss->reduction, ONE_PLY);
+          if (SpNode)
+              alpha = splitPoint->alpha;
+
+          value = -search<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, d, true);
+
+          // Re-search at intermediate depth if reduction is very high
+          if (value > alpha && ss->reduction >= 4 * ONE_PLY)
+          {
+              Depth d2 = std::max(newDepth - 2 * ONE_PLY, ONE_PLY);
+              value = -search<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, d2, true);
+          }
+
+          doFullDepthSearch = (value > alpha && ss->reduction != DEPTH_ZERO);
+          ss->reduction = DEPTH_ZERO;
+      }
+      else
+          doFullDepthSearch = !pvMove;
+
+      // Step 16. Full depth search, when LMR is skipped or fails high
+      if (doFullDepthSearch)
+      {
+          if (SpNode)
+              alpha = splitPoint->alpha;
+
+          value = newDepth < ONE_PLY ?
+                          givesCheck ? -qsearch<NonPV,  true>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
+                                     : -qsearch<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
+                                     : - search<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
+      }
+
+      // For PV nodes only, do a full PV search on the first move or after a fail
+      // high (in the latter case search only if value < beta), otherwise let the
+      // parent node fail low with value <= alpha and to try another move.
+      if (PvNode && (pvMove || (value > alpha && (RootNode || value < beta))))
+          value = newDepth < ONE_PLY ?
+                          givesCheck ? -qsearch<PV,  true>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
+                                     : -qsearch<PV, false>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
+                                     : - search<PV, false>(pos, ss+1, -beta, -alpha, newDepth, false);
+      // Step 17. Undo move
+      pos.undo_move(move);
+
+      assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
+
+      // Step 18. Check for new best move
+      if (SpNode)
+      {
+          splitPoint->mutex.lock();
+          bestValue = splitPoint->bestValue;
+          alpha = splitPoint->alpha;
+      }
+
+      // Finished searching the move. If a stop or a cutoff occurred, the return
+      // value of the search cannot be trusted, and we return immediately without
+      // updating best move, PV and TT.
+      if (Signals.stop || thisThread->cutoff_occurred())
+          return VALUE_ZERO;
+
+      if (RootNode)
+      {
+          RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
+
+          // PV move or new best move ?
+          if (pvMove || value > alpha)
+          {
+              rm.score = value;
+              rm.extract_pv_from_tt(pos);
+
+              // We record how often the best move has been changed in each
+              // iteration. This information is used for time management: When
+              // the best move changes frequently, we allocate some more time.
+              if (!pvMove)
+                  ++BestMoveChanges;
+          }
+          else
+              // All other moves but the PV are set to the lowest value: this is
+              // not a problem when sorting because the sort is stable and the
+              // move position in the list is preserved - just the PV is pushed up.
+              rm.score = -VALUE_INFINITE;
+      }
+
+      if (value > bestValue)
+      {
+          bestValue = SpNode ? splitPoint->bestValue = value : value;
+
+          if (value > alpha)
+          {
+              bestMove = SpNode ? splitPoint->bestMove = move : move;
+
+              if (PvNode && value < beta) // Update alpha! Always alpha < beta
+                  alpha = SpNode ? splitPoint->alpha = value : value;
+              else
+              {
+                  assert(value >= beta); // Fail high
+
+                  if (SpNode)
+                      splitPoint->cutoff = true;
+
+                  break;
+              }
+          }
+      }
+
+      // Step 19. Check for splitting the search
+      if (   !SpNode
+          &&  Threads.size() >= 2
+          &&  depth >= Threads.minimumSplitDepth
+          &&  (   !thisThread->activeSplitPoint
+               || !thisThread->activeSplitPoint->allSlavesSearching)
+          &&  thisThread->splitPointsSize < MAX_SPLITPOINTS_PER_THREAD)
+      {
+          assert(bestValue > -VALUE_INFINITE && bestValue < beta);
+
+          thisThread->split(pos, ss, alpha, beta, &bestValue, &bestMove,
+                            depth, moveCount, &mp, NT, cutNode);
+
+          if (Signals.stop || thisThread->cutoff_occurred())
+              return VALUE_ZERO;
+
+          if (bestValue >= beta)
+              break;
+      }
+    }
+
+    if (SpNode)
+        return bestValue;
+
+    // Following condition would detect a stop or a cutoff set only after move
+    // loop has been completed. But in this case bestValue is valid because we
+    // have fully searched our subtree, and we can anyhow save the result in TT.
+    /*
+       if (Signals.stop || thisThread->cutoff_occurred())
+        return VALUE_DRAW;
+    */
+
+    // Step 20. Check for mate and stalemate
+    // All legal moves have been searched and if there are no legal moves, it
+    // must be mate or stalemate. If we are in a singular extension search then
+    // return a fail low score.
+    if (!moveCount)
+        bestValue = excludedMove ? alpha
+                   :     inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
+
+    // Quiet best move: update killers, history, countermoves and followupmoves
+    else if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck)
+        update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1);
+
+    TT.store(posKey, value_to_tt(bestValue, ss->ply),
+             bestValue >= beta  ? BOUND_LOWER :
+             PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
+             depth, bestMove, ss->staticEval);
+
+    assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
+
+    return bestValue;
+  }
+
+
+  // qsearch() is the quiescence search function, which is called by the main
+  // search function when the remaining depth is zero (or, to be more precise,
+  // less than ONE_PLY).
+
+  template <NodeType NT, bool InCheck>
+  Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
+
+    const bool PvNode = NT == PV;
+
+    assert(NT == PV || NT == NonPV);
+    assert(InCheck == !!pos.checkers());
+    assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
+    assert(PvNode || (alpha == beta - 1));
+    assert(depth <= DEPTH_ZERO);
+
+    StateInfo st;
+    const TTEntry* tte;
+    Key posKey;
+    Move ttMove, move, bestMove;
+    Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
+    bool givesCheck, evasionPrunable;
+    Depth ttDepth;
+
+    // To flag BOUND_EXACT a node with eval above alpha and no available moves
+    if (PvNode)
+        oldAlpha = alpha;
+
+    ss->currentMove = bestMove = MOVE_NONE;
+    ss->ply = (ss-1)->ply + 1;
+
+    // Check for an instant draw or if the maximum ply has been reached
+    if (pos.is_draw() || ss->ply > MAX_PLY)
+        return ss->ply > MAX_PLY && !InCheck ? evaluate(pos) : DrawValue[pos.side_to_move()];
+
+    // Decide whether or not to include checks: this fixes also the type of
+    // TT entry depth that we are going to use. Note that in qsearch we use
+    // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
+    ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
+                                                  : DEPTH_QS_NO_CHECKS;
+
+    // Transposition table lookup
+    posKey = pos.key();
+    tte = TT.probe(posKey);
+    ttMove = tte ? tte->move() : MOVE_NONE;
+    ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_NONE;
+
+    if (   tte
+        && tte->depth() >= ttDepth
+        && ttValue != VALUE_NONE // Only in case of TT access race
+        && (           PvNode ?  tte->bound() == BOUND_EXACT
+            : ttValue >= beta ? (tte->bound() &  BOUND_LOWER)
+                              : (tte->bound() &  BOUND_UPPER)))
+    {
+        ss->currentMove = ttMove; // Can be MOVE_NONE
+        return ttValue;
+    }
+
+    // Evaluate the position statically
+    if (InCheck)
+    {
+        ss->staticEval = VALUE_NONE;
+        bestValue = futilityBase = -VALUE_INFINITE;
+    }
+    else
+    {
+        if (tte)
+        {
+            // Never assume anything on values stored in TT
+            if ((ss->staticEval = bestValue = tte->eval_value()) == VALUE_NONE)
+                ss->staticEval = bestValue = evaluate(pos);
+
+            // Can ttValue be used as a better position evaluation?
+            if (ttValue != VALUE_NONE)
+                if (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))
+                    bestValue = ttValue;
+        }
+        else
+            ss->staticEval = bestValue =
+            (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Eval::Tempo;
+
+        // Stand pat. Return immediately if static value is at least beta
+        if (bestValue >= beta)
+        {
+            if (!tte)
+                TT.store(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
+                         DEPTH_NONE, MOVE_NONE, ss->staticEval);
+
+            return bestValue;
+        }
+
+        if (PvNode && bestValue > alpha)
+            alpha = bestValue;
+
+        futilityBase = bestValue + 128;
+    }
+
+    // Initialize a MovePicker object for the current position, and prepare
+    // to search the moves. Because the depth is <= 0 here, only captures,
+    // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
+    // be generated.
+    MovePicker mp(pos, ttMove, depth, History, to_sq((ss-1)->currentMove));
+    CheckInfo ci(pos);
+
+    // Loop through the moves until no moves remain or a beta cutoff occurs
+    while ((move = mp.next_move<false>()) != MOVE_NONE)
+    {
+      assert(is_ok(move));
+
+      givesCheck =  type_of(move) == NORMAL && !ci.dcCandidates
+                  ? ci.checkSq[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
+                  : pos.gives_check(move, ci);
+
+      // Futility pruning
+      if (   !PvNode
+          && !InCheck
+          && !givesCheck
+          &&  move != ttMove
+          &&  futilityBase > -VALUE_KNOWN_WIN
+          && !pos.advanced_pawn_push(move))
+      {
+          assert(type_of(move) != ENPASSANT); // Due to !pos.advanced_pawn_push
+
+          futilityValue = futilityBase + PieceValue[EG][pos.piece_on(to_sq(move))];
+
+          if (futilityValue < beta)
+          {
+              bestValue = std::max(bestValue, futilityValue);
+              continue;
+          }
+
+          if (futilityBase < beta && pos.see(move) <= VALUE_ZERO)
+          {
+              bestValue = std::max(bestValue, futilityBase);
+              continue;
+          }
+      }
+
+      // Detect non-capture evasions that are candidates to be pruned
+      evasionPrunable =    InCheck
+                       &&  bestValue > VALUE_MATED_IN_MAX_PLY
+                       && !pos.capture(move)
+                       && !pos.can_castle(pos.side_to_move());
+
+      // Don't search moves with negative SEE values
+      if (   !PvNode
+          && (!InCheck || evasionPrunable)
+          &&  move != ttMove
+          &&  type_of(move) != PROMOTION
+          &&  pos.see_sign(move) < VALUE_ZERO)
+          continue;
+
+      // Check for legality just before making the move
+      if (!pos.legal(move, ci.pinned))
+          continue;
+
+      ss->currentMove = move;
+
+      // Make and search the move
+      pos.do_move(move, st, ci, givesCheck);
+      value = givesCheck ? -qsearch<NT,  true>(pos, ss+1, -beta, -alpha, depth - ONE_PLY)
+                         : -qsearch<NT, false>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
+      pos.undo_move(move);
+
+      assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
+
+      // Check for new best move
+      if (value > bestValue)
+      {
+          bestValue = value;
+
+          if (value > alpha)
+          {
+              if (PvNode && value < beta) // Update alpha here! Always alpha < beta
+              {
+                  alpha = value;
+                  bestMove = move;
+              }
+              else // Fail high
+              {
+                  TT.store(posKey, value_to_tt(value, ss->ply), BOUND_LOWER,
+                           ttDepth, move, ss->staticEval);
+
+                  return value;
+              }
+          }
+       }
+    }
+
+    // All legal moves have been searched. A special case: If we're in check
+    // and no legal moves were found, it is checkmate.
+    if (InCheck && bestValue == -VALUE_INFINITE)
+        return mated_in(ss->ply); // Plies to mate from the root
+
+    TT.store(posKey, value_to_tt(bestValue, ss->ply),
+             PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
+             ttDepth, bestMove, ss->staticEval);
+
+    assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
+
+    return bestValue;
+  }
+
+
+  // value_to_tt() adjusts a mate score from "plies to mate from the root" to
+  // "plies to mate from the current position". Non-mate scores are unchanged.
+  // The function is called before storing a value in the transposition table.
+
+  Value value_to_tt(Value v, int ply) {
+
+    assert(v != VALUE_NONE);
+
+    return  v >= VALUE_MATE_IN_MAX_PLY  ? v + ply
+          : v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v;
+  }
+
+
+  // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
+  // from the transposition table (which refers to the plies to mate/be mated
+  // from current position) to "plies to mate/be mated from the root".
+
+  Value value_from_tt(Value v, int ply) {
+
+    return  v == VALUE_NONE             ? VALUE_NONE
+          : v >= VALUE_MATE_IN_MAX_PLY  ? v - ply
+          : v <= VALUE_MATED_IN_MAX_PLY ? v + ply : v;
+  }
+
+
+  // update_stats() updates killers, history, countermoves and followupmoves stats after a fail-high
+  // of a quiet move.
+
+  void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) {
+
+    if (ss->killers[0] != move)
+    {
+        ss->killers[1] = ss->killers[0];
+        ss->killers[0] = move;
+    }
+
+    // Increase history value of the cut-off move and decrease all the other
+    // played quiet moves.
+    Value bonus = Value(int(depth) * int(depth));
+    History.update(pos.moved_piece(move), to_sq(move), bonus);
+    for (int i = 0; i < quietsCnt; ++i)
+    {
+        Move m = quiets[i];
+        History.update(pos.moved_piece(m), to_sq(m), -bonus);
+    }
+
+    if (is_ok((ss-1)->currentMove))
+    {
+        Square prevMoveSq = to_sq((ss-1)->currentMove);
+        Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, move);
+    }
+
+    if (is_ok((ss-2)->currentMove) && (ss-1)->currentMove == (ss-1)->ttMove)
+    {
+        Square prevOwnMoveSq = to_sq((ss-2)->currentMove);
+        Followupmoves.update(pos.piece_on(prevOwnMoveSq), prevOwnMoveSq, move);
+    }
+  }
+
+
+  // When playing with a strength handicap, choose best move among the first 'candidates'
+  // RootMoves using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
+
+  Move Skill::pick_move() {
+
+    static RKISS rk;
+
+    // PRNG sequence should be not deterministic
+    for (int i = Time::now() % 50; i > 0; --i)
+        rk.rand<unsigned>();
+
+    // RootMoves are already sorted by score in descending order
+    int variance = std::min(RootMoves[0].score - RootMoves[candidates - 1].score, PawnValueMg);
+    int weakness = 120 - 2 * level;
+    int max_s = -VALUE_INFINITE;
+    best = MOVE_NONE;
+
+    // Choose best move. For each move score we add two terms both dependent on
+    // weakness. One deterministic and bigger for weaker moves, and one random,
+    // then we choose the move with the resulting highest score.
+    for (size_t i = 0; i < candidates; ++i)
+    {
+        int s = RootMoves[i].score;
+
+        // Don't allow crazy blunders even at very low skills
+        if (i > 0 && RootMoves[i - 1].score > s + 2 * PawnValueMg)
+            break;
+
+        // This is our magic formula
+        s += (  weakness * int(RootMoves[0].score - s)
+              + variance * (rk.rand<unsigned>() % weakness)) / 128;
+
+        if (s > max_s)
+        {
+            max_s = s;
+            best = RootMoves[i].pv[0];
+        }
+    }
+    return best;
+  }
+
+
+  // uci_pv() formats PV information according to the UCI protocol. UCI
+  // requires that all (if any) unsearched PV lines are sent using a previous
+  // search score.
+
+  string uci_pv(const Position& pos, int depth, Value alpha, Value beta) {
+
+    std::stringstream ss;
+    Time::point elapsed = Time::now() - SearchTime + 1;
+    size_t uciPVSize = std::min((size_t)Options["MultiPV"], RootMoves.size());
+    int selDepth = 0;
+
+    for (size_t i = 0; i < Threads.size(); ++i)
+        if (Threads[i]->maxPly > selDepth)
+            selDepth = Threads[i]->maxPly;
+
+    for (size_t i = 0; i < uciPVSize; ++i)
+    {
+        bool updated = (i <= PVIdx);
+
+        if (depth == 1 && !updated)
+            continue;
+
+        int d   = updated ? depth : depth - 1;
+        Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore;
+
+        if (ss.rdbuf()->in_avail()) // Not at first line
+            ss << "\n";
+
+        ss << "info depth " << d
+           << " seldepth "  << selDepth
+           << " score "     << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v))
+           << " nodes "     << pos.nodes_searched()
+           << " nps "       << pos.nodes_searched() * 1000 / elapsed
+           << " time "      << elapsed
+           << " multipv "   << i + 1
+           << " pv";
+
+        for (size_t j = 0; RootMoves[i].pv[j] != MOVE_NONE; ++j)
+            ss << " " << move_to_uci(RootMoves[i].pv[j], pos.is_chess960());
+    }
+
+    return ss.str();
+  }
+
+} // namespace
+
+
+/// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table.
+/// We also consider both failing high nodes and BOUND_EXACT nodes here to
+/// ensure that we have a ponder move even when we fail high at root. This
+/// results in a long PV to print that is important for position analysis.
+
+void RootMove::extract_pv_from_tt(Position& pos) {
+
+  StateInfo state[MAX_PLY_PLUS_6], *st = state;
+  const TTEntry* tte;
+  int ply = 1;    // At root ply is 1...
+  Move m = pv[0]; // ...instead pv[] array starts from 0
+  Value expectedScore = score;
+
+  pv.clear();
+
+  do {
+      pv.push_back(m);
+
+      assert(MoveList<LEGAL>(pos).contains(pv[ply - 1]));
+
+      pos.do_move(pv[ply++ - 1], *st++);
+      tte = TT.probe(pos.key());
+      expectedScore = -expectedScore;
+
+  } while (   tte
+           && expectedScore == value_from_tt(tte->value(), ply)
+           && pos.pseudo_legal(m = tte->move()) // Local copy, TT could change
+           && pos.legal(m, pos.pinned_pieces(pos.side_to_move()))
+           && ply < MAX_PLY
+           && (!pos.is_draw() || ply <= 2));
+
+  pv.push_back(MOVE_NONE); // Must be zero-terminating
+
+  while (--ply) pos.undo_move(pv[ply - 1]);
+}
+
+
+/// RootMove::insert_pv_in_tt() is called at the end of a search iteration, and
+/// inserts the PV back into the TT. This makes sure the old PV moves are searched
+/// first, even if the old TT entries have been overwritten.
+
+void RootMove::insert_pv_in_tt(Position& pos) {
+
+  StateInfo state[MAX_PLY_PLUS_6], *st = state;
+  const TTEntry* tte;
+  int idx = 0; // Ply starts from 1, we need to start from 0
+
+  do {
+      tte = TT.probe(pos.key());
+
+      if (!tte || tte->move() != pv[idx]) // Don't overwrite correct entries
+          TT.store(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[idx], VALUE_NONE);
+
+      assert(MoveList<LEGAL>(pos).contains(pv[idx]));
+
+      pos.do_move(pv[idx++], *st++);
+
+  } while (pv[idx] != MOVE_NONE);
+
+  while (idx) pos.undo_move(pv[--idx]);
+}
+
+
+/// Thread::idle_loop() is where the thread is parked when it has no work to do
+
+void Thread::idle_loop() {
+
+  // Pointer 'this_sp' is not null only if we are called from split(), and not
+  // at the thread creation. This means we are the split point's master.
+  SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL;
+
+  assert(!this_sp || (this_sp->masterThread == this && searching));
+
+  while (true)
+  {
+      // If we are not searching, wait for a condition to be signaled instead of
+      // wasting CPU time polling for work.
+      while (!searching || exit)
+      {
+          if (exit)
+          {
+              assert(!this_sp);
+              return;
+          }
+
+          // Grab the lock to avoid races with Thread::notify_one()
+          mutex.lock();
+
+          // If we are master and all slaves have finished then exit idle_loop
+          if (this_sp && this_sp->slavesMask.none())
+          {
+              mutex.unlock();
+              break;
+          }
+
+          // Do sleep after retesting sleep conditions under lock protection. In
+          // particular we need to avoid a deadlock in case a master thread has,
+          // in the meanwhile, allocated us and sent the notify_one() call before
+          // we had the chance to grab the lock.
+          if (!searching && !exit)
+              sleepCondition.wait(mutex);
+
+          mutex.unlock();
+      }
+
+      // If this thread has been assigned work, launch a search
+      if (searching)
+      {
+          assert(!exit);
+
+          Threads.mutex.lock();
+
+          assert(searching);
+          assert(activeSplitPoint);
+          SplitPoint* sp = activeSplitPoint;
+
+          Threads.mutex.unlock();
+
+          Stack stack[MAX_PLY_PLUS_6], *ss = stack+2; // To allow referencing (ss-2)
+          Position pos(*sp->pos, this);
+
+          std::memcpy(ss-2, sp->ss-2, 5 * sizeof(Stack));
+          ss->splitPoint = sp;
+
+          sp->mutex.lock();
+
+          assert(activePosition == NULL);
+
+          activePosition = &pos;
+
+          if (sp->nodeType == NonPV)
+              search<NonPV, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
+
+          else if (sp->nodeType == PV)
+              search<PV, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
+
+          else if (sp->nodeType == Root)
+              search<Root, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
+
+          else
+              assert(false);
+
+          assert(searching);
+
+          searching = false;
+          activePosition = NULL;
+          sp->slavesMask.reset(idx);
+          sp->allSlavesSearching = false;
+          sp->nodes += pos.nodes_searched();
+
+          // Wake up the master thread so to allow it to return from the idle
+          // loop in case we are the last slave of the split point.
+          if (    this != sp->masterThread
+              &&  sp->slavesMask.none())
+          {
+              assert(!sp->masterThread->searching);
+              sp->masterThread->notify_one();
+          }
+
+          // After releasing the lock we can't access any SplitPoint related data
+          // in a safe way because it could have been released under our feet by
+          // the sp master.
+          sp->mutex.unlock();
+
+          // Try to late join to another split point if none of its slaves has
+          // already finished.
+          if (Threads.size() > 2)
+              for (size_t i = 0; i < Threads.size(); ++i)
+              {
+                  const int size = Threads[i]->splitPointsSize; // Local copy
+                  sp = size ? &Threads[i]->splitPoints[size - 1] : NULL;
+
+                  if (   sp
+                      && sp->allSlavesSearching
+                      && available_to(Threads[i]))
+                  {
+                      // Recheck the conditions under lock protection
+                      Threads.mutex.lock();
+                      sp->mutex.lock();
+
+                      if (   sp->allSlavesSearching
+                          && available_to(Threads[i]))
+                      {
+                           sp->slavesMask.set(idx);
+                           activeSplitPoint = sp;
+                           searching = true;
+                      }
+
+                      sp->mutex.unlock();
+                      Threads.mutex.unlock();
+
+                      break; // Just a single attempt
+                  }
+              }
+      }
+
+      // If this thread is the master of a split point and all slaves have finished
+      // their work at this split point, return from the idle loop.
+      if (this_sp && this_sp->slavesMask.none())
+      {
+          this_sp->mutex.lock();
+          bool finished = this_sp->slavesMask.none(); // Retest under lock protection
+          this_sp->mutex.unlock();
+          if (finished)
+              return;
+      }
+  }
+}
+
+
+/// check_time() is called by the timer thread when the timer triggers. It is
+/// used to print debug info and, more importantly, to detect when we are out of
+/// available time and thus stop the search.
+
+void check_time() {
+
+  static Time::point lastInfoTime = Time::now();
+  int64_t nodes = 0; // Workaround silly 'uninitialized' gcc warning
+
+  if (Time::now() - lastInfoTime >= 1000)
+  {
+      lastInfoTime = Time::now();
+      dbg_print();
+  }
+
+  if (Limits.ponder)
+      return;
+
+  if (Limits.nodes)
+  {
+      Threads.mutex.lock();
+
+      nodes = RootPos.nodes_searched();
+
+      // Loop across all split points and sum accumulated SplitPoint nodes plus
+      // all the currently active positions nodes.
+      for (size_t i = 0; i < Threads.size(); ++i)
+          for (int j = 0; j < Threads[i]->splitPointsSize; ++j)
+          {
+              SplitPoint& sp = Threads[i]->splitPoints[j];
+
+              sp.mutex.lock();
+
+              nodes += sp.nodes;
+
+              for (size_t idx = 0; idx < Threads.size(); ++idx)
+                  if (sp.slavesMask.test(idx) && Threads[idx]->activePosition)
+                      nodes += Threads[idx]->activePosition->nodes_searched();
+
+              sp.mutex.unlock();
+          }
+
+      Threads.mutex.unlock();
+  }
+
+  Time::point elapsed = Time::now() - SearchTime;
+  bool stillAtFirstMove =    Signals.firstRootMove
+                         && !Signals.failedLowAtRoot
+                         &&  elapsed > TimeMgr.available_time() * 75 / 100;
+
+  bool noMoreTime =   elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution
+                   || stillAtFirstMove;
+
+  if (   (Limits.use_time_management() && noMoreTime)
+      || (Limits.movetime && elapsed >= Limits.movetime)
+      || (Limits.nodes && nodes >= Limits.nodes))
+      Signals.stop = true;
+}
diff --git a/src/search.h b/src/search.h
new file mode 100644 (file)
index 0000000..4fe5a5b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SEARCH_H_INCLUDED
+#define SEARCH_H_INCLUDED
+
+#include <memory>
+#include <stack>
+#include <vector>
+
+#include "misc.h"
+#include "position.h"
+#include "types.h"
+
+struct SplitPoint;
+
+namespace Search {
+
+/// The Stack struct keeps track of the information we need to remember from
+/// nodes shallower and deeper in the tree during the search. Each search thread
+/// has its own array of Stack objects, indexed by the current ply.
+
+struct Stack {
+  SplitPoint* splitPoint;
+  int ply;
+  Move currentMove;
+  Move ttMove;
+  Move excludedMove;
+  Move killers[2];
+  Depth reduction;
+  Value staticEval;
+  bool skipNullMove;
+};
+
+
+/// RootMove struct is used for moves at the root of the tree. For each root
+/// move we store a score, a node count, and a PV (really a refutation in the
+/// case of moves which fail low). Score is normally set at -VALUE_INFINITE for
+/// all non-pv moves.
+struct RootMove {
+
+  RootMove(Move m) : score(-VALUE_INFINITE), prevScore(-VALUE_INFINITE) {
+    pv.push_back(m); pv.push_back(MOVE_NONE);
+  }
+
+  bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort
+  bool operator==(const Move& m) const { return pv[0] == m; }
+
+  void extract_pv_from_tt(Position& pos);
+  void insert_pv_in_tt(Position& pos);
+
+  Value score;
+  Value prevScore;
+  std::vector<Move> pv;
+};
+
+
+/// The LimitsType struct stores information sent by GUI about available time
+/// to search the current move, maximum depth/time, if we are in analysis mode
+/// or if we have to ponder while it's our opponent's turn to move.
+
+struct LimitsType {
+
+  LimitsType() { // Using memset on a std::vector is undefined behavior
+    time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = movestogo =
+    depth = nodes = movetime = mate = infinite = ponder = 0;
+  }
+  bool use_time_management() const { return !(mate | movetime | depth | nodes | infinite); }
+
+  std::vector<Move> searchmoves;
+  int time[COLOR_NB], inc[COLOR_NB], movestogo, depth, nodes, movetime, mate, infinite, ponder;
+};
+
+
+/// The SignalsType struct stores volatile flags updated during the search
+/// typically in an async fashion e.g. to stop the search by the GUI.
+
+struct SignalsType {
+  bool stop, stopOnPonderhit, firstRootMove, failedLowAtRoot;
+};
+
+typedef std::auto_ptr<std::stack<StateInfo> > StateStackPtr;
+
+extern volatile SignalsType Signals;
+extern LimitsType Limits;
+extern std::vector<RootMove> RootMoves;
+extern Position RootPos;
+extern Time::point SearchTime;
+extern StateStackPtr SetupStates;
+
+extern void init();
+extern void think();
+template<bool Root> uint64_t perft(Position& pos, Depth depth);
+
+} // namespace Search
+
+#endif // #ifndef SEARCH_H_INCLUDED
diff --git a/src/thread.cpp b/src/thread.cpp
new file mode 100644 (file)
index 0000000..3b98ac6
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm> // For std::count
+#include <cassert>
+
+#include "movegen.h"
+#include "search.h"
+#include "thread.h"
+#include "ucioption.h"
+
+using namespace Search;
+
+ThreadPool Threads; // Global object
+
+extern void check_time();
+
+namespace {
+
+ // start_routine() is the C function which is called when a new thread
+ // is launched. It is a wrapper to the virtual function idle_loop().
+
+ extern "C" { long start_routine(ThreadBase* th) { th->idle_loop(); return 0; } }
+
+
+ // Helpers to launch a thread after creation and joining before delete. Must be
+ // outside Thread c'tor and d'tor because the object will be fully initialized
+ // when start_routine (and hence virtual idle_loop) is called and when joining.
+
+ template<typename T> T* new_thread() {
+   T* th = new T();
+   thread_create(th->handle, start_routine, th); // Will go to sleep
+   return th;
+ }
+
+ void delete_thread(ThreadBase* th) {
+   th->exit = true; // Search must be already finished
+   th->notify_one();
+   thread_join(th->handle); // Wait for thread termination
+   delete th;
+ }
+
+}
+
+
+// notify_one() wakes up the thread when there is some work to do
+
+void ThreadBase::notify_one() {
+
+  mutex.lock();
+  sleepCondition.notify_one();
+  mutex.unlock();
+}
+
+
+// wait_for() set the thread to sleep until condition 'b' turns true
+
+void ThreadBase::wait_for(volatile const bool& b) {
+
+  mutex.lock();
+  while (!b) sleepCondition.wait(mutex);
+  mutex.unlock();
+}
+
+
+// Thread c'tor just inits data and does not launch any execution thread.
+// Such a thread will only be started when c'tor returns.
+
+Thread::Thread() /* : splitPoints() */ { // Value-initialization bug in MSVC
+
+  searching = false;
+  maxPly = splitPointsSize = 0;
+  activeSplitPoint = NULL;
+  activePosition = NULL;
+  idx = Threads.size(); // Starts from 0
+}
+
+
+// cutoff_occurred() checks whether a beta cutoff has occurred in the
+// current active split point, or in some ancestor of the split point.
+
+bool Thread::cutoff_occurred() const {
+
+  for (SplitPoint* sp = activeSplitPoint; sp; sp = sp->parentSplitPoint)
+      if (sp->cutoff)
+          return true;
+
+  return false;
+}
+
+
+// Thread::available_to() checks whether the thread is available to help the
+// thread 'master' at a split point. An obvious requirement is that thread must
+// be idle. With more than two threads, this is not sufficient: If the thread is
+// the master of some split point, it is only available as a slave to the slaves
+// which are busy searching the split point at the top of slave's split point
+// stack (the "helpful master concept" in YBWC terminology).
+
+bool Thread::available_to(const Thread* master) const {
+
+  if (searching)
+      return false;
+
+  // Make a local copy to be sure it doesn't become zero under our feet while
+  // testing next condition and so leading to an out of bounds access.
+  const int size = splitPointsSize;
+
+  // No split points means that the thread is available as a slave for any
+  // other thread otherwise apply the "helpful master" concept if possible.
+  return !size || splitPoints[size - 1].slavesMask.test(master->idx);
+}
+
+
+// TimerThread::idle_loop() is where the timer thread waits msec milliseconds
+// and then calls check_time(). If msec is 0 thread sleeps until it's woken up.
+
+void TimerThread::idle_loop() {
+
+  while (!exit)
+  {
+      mutex.lock();
+
+      if (!exit)
+          sleepCondition.wait_for(mutex, run ? Resolution : INT_MAX);
+
+      mutex.unlock();
+
+      if (run)
+          check_time();
+  }
+}
+
+
+// MainThread::idle_loop() is where the main thread is parked waiting to be started
+// when there is a new search. The main thread will launch all the slave threads.
+
+void MainThread::idle_loop() {
+
+  while (true)
+  {
+      mutex.lock();
+
+      thinking = false;
+
+      while (!thinking && !exit)
+      {
+          Threads.sleepCondition.notify_one(); // Wake up the UI thread if needed
+          sleepCondition.wait(mutex);
+      }
+
+      mutex.unlock();
+
+      if (exit)
+          return;
+
+      searching = true;
+
+      Search::think();
+
+      assert(searching);
+
+      searching = false;
+  }
+}
+
+
+// init() is called at startup to create and launch requested threads, that will
+// go immediately to sleep. We cannot use a c'tor because Threads is a static
+// object and we need a fully initialized engine at this point due to allocation
+// of Endgames in Thread c'tor.
+
+void ThreadPool::init() {
+
+  timer = new_thread<TimerThread>();
+  push_back(new_thread<MainThread>());
+  read_uci_options();
+}
+
+
+// exit() cleanly terminates the threads before the program exits. Cannot be done in
+// d'tor because we have to terminate the threads before to free ThreadPool object.
+
+void ThreadPool::exit() {
+
+  delete_thread(timer); // As first because check_time() accesses threads data
+
+  for (iterator it = begin(); it != end(); ++it)
+      delete_thread(*it);
+}
+
+
+// read_uci_options() updates internal threads parameters from the corresponding
+// UCI options and creates/destroys threads to match the requested number. Thread
+// objects are dynamically allocated to avoid creating all possible threads
+// in advance (which include pawns and material tables), even if only a few
+// are to be used.
+
+void ThreadPool::read_uci_options() {
+
+  minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY;
+  size_t requested  = Options["Threads"];
+
+  assert(requested > 0);
+
+  // If zero (default) then set best minimum split depth automatically
+  if (!minimumSplitDepth)
+      minimumSplitDepth = requested < 8 ? 4 * ONE_PLY : 7 * ONE_PLY;
+
+  while (size() < requested)
+      push_back(new_thread<Thread>());
+
+  while (size() > requested)
+  {
+      delete_thread(back());
+      pop_back();
+  }
+}
+
+
+// available_slave() tries to find an idle thread which is available as a slave
+// for the thread 'master'.
+
+Thread* ThreadPool::available_slave(const Thread* master) const {
+
+  for (const_iterator it = begin(); it != end(); ++it)
+      if ((*it)->available_to(master))
+          return *it;
+
+  return NULL;
+}
+
+
+// split() does the actual work of distributing the work at a node between
+// several available threads. If it does not succeed in splitting the node
+// (because no idle threads are available), the function immediately returns.
+// If splitting is possible, a SplitPoint object is initialized with all the
+// data that must be copied to the helper threads and then helper threads are
+// told that they have been assigned work. This will cause them to instantly
+// leave their idle loops and call search(). When all threads have returned from
+// search() then split() returns.
+
+void Thread::split(Position& pos, const Stack* ss, Value alpha, Value beta, Value* bestValue,
+                   Move* bestMove, Depth depth, int moveCount,
+                   MovePicker* movePicker, int nodeType, bool cutNode) {
+
+  assert(pos.pos_is_ok());
+  assert(-VALUE_INFINITE < *bestValue && *bestValue <= alpha && alpha < beta && beta <= VALUE_INFINITE);
+  assert(depth >= Threads.minimumSplitDepth);
+  assert(searching);
+  assert(splitPointsSize < MAX_SPLITPOINTS_PER_THREAD);
+
+  // Pick the next available split point from the split point stack
+  SplitPoint& sp = splitPoints[splitPointsSize];
+
+  sp.masterThread = this;
+  sp.parentSplitPoint = activeSplitPoint;
+  sp.slavesMask = 0, sp.slavesMask.set(idx);
+  sp.depth = depth;
+  sp.bestValue = *bestValue;
+  sp.bestMove = *bestMove;
+  sp.alpha = alpha;
+  sp.beta = beta;
+  sp.nodeType = nodeType;
+  sp.cutNode = cutNode;
+  sp.movePicker = movePicker;
+  sp.moveCount = moveCount;
+  sp.pos = &pos;
+  sp.nodes = 0;
+  sp.cutoff = false;
+  sp.ss = ss;
+
+  // Try to allocate available threads and ask them to start searching setting
+  // 'searching' flag. This must be done under lock protection to avoid concurrent
+  // allocation of the same slave by another master.
+  Threads.mutex.lock();
+  sp.mutex.lock();
+
+  sp.allSlavesSearching = true; // Must be set under lock protection
+  ++splitPointsSize;
+  activeSplitPoint = &sp;
+  activePosition = NULL;
+
+  for (Thread* slave; (slave = Threads.available_slave(this)) != NULL; )
+  {
+      sp.slavesMask.set(slave->idx);
+      slave->activeSplitPoint = &sp;
+      slave->searching = true; // Slave leaves idle_loop()
+      slave->notify_one(); // Could be sleeping
+  }
+
+  // Everything is set up. The master thread enters the idle loop, from which
+  // it will instantly launch a search, because its 'searching' flag is set.
+  // The thread will return from the idle loop when all slaves have finished
+  // their work at this split point.
+  sp.mutex.unlock();
+  Threads.mutex.unlock();
+
+  Thread::idle_loop(); // Force a call to base class idle_loop()
+
+  // In the helpful master concept, a master can help only a sub-tree of its
+  // split point and because everything is finished here, it's not possible
+  // for the master to be booked.
+  assert(!searching);
+  assert(!activePosition);
+
+  // We have returned from the idle loop, which means that all threads are
+  // finished. Note that setting 'searching' and decreasing splitPointsSize is
+  // done under lock protection to avoid a race with Thread::available_to().
+  Threads.mutex.lock();
+  sp.mutex.lock();
+
+  searching = true;
+  --splitPointsSize;
+  activeSplitPoint = sp.parentSplitPoint;
+  activePosition = &pos;
+  pos.set_nodes_searched(pos.nodes_searched() + sp.nodes);
+  *bestMove = sp.bestMove;
+  *bestValue = sp.bestValue;
+
+  sp.mutex.unlock();
+  Threads.mutex.unlock();
+}
+
+// wait_for_think_finished() waits for main thread to go to sleep then returns
+
+void ThreadPool::wait_for_think_finished() {
+
+  MainThread* t = main();
+  t->mutex.lock();
+  while (t->thinking) sleepCondition.wait(t->mutex);
+  t->mutex.unlock();
+}
+
+
+// start_thinking() wakes up the main thread sleeping in MainThread::idle_loop()
+// so to start a new search, then returns immediately.
+
+void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits, StateStackPtr& states) {
+
+  wait_for_think_finished();
+
+  SearchTime = Time::now(); // As early as possible
+
+  Signals.stopOnPonderhit = Signals.firstRootMove = false;
+  Signals.stop = Signals.failedLowAtRoot = false;
+
+  RootMoves.clear();
+  RootPos = pos;
+  Limits = limits;
+  if (states.get()) // If we don't set a new position, preserve current state
+  {
+      SetupStates = states; // Ownership transfer here
+      assert(!states.get());
+  }
+
+  for (MoveList<LEGAL> it(pos); *it; ++it)
+      if (   limits.searchmoves.empty()
+          || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), *it))
+          RootMoves.push_back(RootMove(*it));
+
+  main()->thinking = true;
+  main()->notify_one(); // Starts main thread
+}
diff --git a/src/thread.h b/src/thread.h
new file mode 100644 (file)
index 0000000..26aed39
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef THREAD_H_INCLUDED
+#define THREAD_H_INCLUDED
+
+#include <bitset>
+#include <vector>
+
+#include "material.h"
+#include "movepick.h"
+#include "pawns.h"
+#include "position.h"
+#include "search.h"
+
+const int MAX_THREADS = 128;
+const int MAX_SPLITPOINTS_PER_THREAD = 8;
+
+struct Mutex {
+  Mutex() { lock_init(l); }
+ ~Mutex() { lock_destroy(l); }
+
+  void lock() { lock_grab(l); }
+  void unlock() { lock_release(l); }
+
+private:
+  friend struct ConditionVariable;
+
+  Lock l;
+};
+
+struct ConditionVariable {
+  ConditionVariable() { cond_init(c); }
+ ~ConditionVariable() { cond_destroy(c); }
+
+  void wait(Mutex& m) { cond_wait(c, m.l); }
+  void wait_for(Mutex& m, int ms) { timed_wait(c, m.l, ms); }
+  void notify_one() { cond_signal(c); }
+
+private:
+  WaitCondition c;
+};
+
+struct Thread;
+
+struct SplitPoint {
+
+  // Const data after split point has been setup
+  const Position* pos;
+  const Search::Stack* ss;
+  Thread* masterThread;
+  Depth depth;
+  Value beta;
+  int nodeType;
+  bool cutNode;
+
+  // Const pointers to shared data
+  MovePicker* movePicker;
+  SplitPoint* parentSplitPoint;
+
+  // Shared data
+  Mutex mutex;
+  std::bitset<MAX_THREADS> slavesMask;
+  volatile bool allSlavesSearching;
+  volatile uint64_t nodes;
+  volatile Value alpha;
+  volatile Value bestValue;
+  volatile Move bestMove;
+  volatile int moveCount;
+  volatile bool cutoff;
+};
+
+
+/// ThreadBase struct is the base of the hierarchy from where we derive all the
+/// specialized thread classes.
+
+struct ThreadBase {
+
+  ThreadBase() : handle(NativeHandle()), exit(false) {}
+  virtual ~ThreadBase() {}
+  virtual void idle_loop() = 0;
+  void notify_one();
+  void wait_for(volatile const bool& b);
+
+  Mutex mutex;
+  ConditionVariable sleepCondition;
+  NativeHandle handle;
+  volatile bool exit;
+};
+
+
+/// Thread struct keeps together all the thread related stuff like locks, state
+/// and especially split points. We also use per-thread pawn and material hash
+/// tables so that once we get a pointer to an entry its life time is unlimited
+/// and we don't have to care about someone changing the entry under our feet.
+
+struct Thread : public ThreadBase {
+
+  Thread();
+  virtual void idle_loop();
+  bool cutoff_occurred() const;
+  bool available_to(const Thread* master) const;
+
+  void split(Position& pos, const Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
+             Depth depth, int moveCount, MovePicker* movePicker, int nodeType, bool cutNode);
+
+  SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD];
+  Material::Table materialTable;
+  Endgames endgames;
+  Pawns::Table pawnsTable;
+  Position* activePosition;
+  size_t idx;
+  int maxPly;
+  SplitPoint* volatile activeSplitPoint;
+  volatile int splitPointsSize;
+  volatile bool searching;
+};
+
+
+/// MainThread and TimerThread are derived classes used to characterize the two
+/// special threads: the main one and the recurring timer.
+
+struct MainThread : public Thread {
+  MainThread() : thinking(true) {} // Avoid a race with start_thinking()
+  virtual void idle_loop();
+  volatile bool thinking;
+};
+
+struct TimerThread : public ThreadBase {
+  TimerThread() : run(false) {}
+  virtual void idle_loop();
+  bool run;
+  static const int Resolution = 5; // msec between two check_time() calls
+};
+
+
+/// ThreadPool struct handles all the threads related stuff like init, starting,
+/// parking and, most importantly, launching a slave thread at a split point.
+/// All the access to shared thread data is done through this class.
+
+struct ThreadPool : public std::vector<Thread*> {
+
+  void init(); // No c'tor and d'tor, threads rely on globals that should
+  void exit(); // be initialized and are valid during the whole thread lifetime.
+
+  MainThread* main() { return static_cast<MainThread*>((*this)[0]); }
+  void read_uci_options();
+  Thread* available_slave(const Thread* master) const;
+  void wait_for_think_finished();
+  void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&);
+
+  Depth minimumSplitDepth;
+  Mutex mutex;
+  ConditionVariable sleepCondition;
+  TimerThread* timer;
+};
+
+extern ThreadPool Threads;
+
+#endif // #ifndef THREAD_H_INCLUDED
diff --git a/src/timeman.cpp b/src/timeman.cpp
new file mode 100644 (file)
index 0000000..c305e61
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+
+#include "search.h"
+#include "timeman.h"
+#include "ucioption.h"
+
+namespace {
+
+  enum TimeType { OptimumTime, MaxTime };
+
+  const int MoveHorizon   = 50;   // Plan time management at most this many moves ahead
+  const double MaxRatio   = 7.0;  // When in trouble, we can step over reserved time with this ratio
+  const double StealRatio = 0.33; // However we must not steal time from remaining moves over this ratio
+
+  const double xscale     = 9.3;
+  const double xshift     = 59.8;
+  const double skewfactor = 0.172;
+
+
+  // move_importance() is a skew-logistic function based on naive statistical
+  // analysis of "how many games are still undecided after n half-moves". Game
+  // is considered "undecided" as long as neither side has >275cp advantage.
+  // Data was extracted from CCRL game database with some simple filtering criteria.
+
+  double move_importance(int ply) {
+
+    return pow((1 + exp((ply - xshift) / xscale)), -skewfactor) + DBL_MIN; // Ensure non-zero
+  }
+
+  template<TimeType T>
+  int remaining(int myTime, int movesToGo, int currentPly, int slowMover)
+  {
+    const double TMaxRatio   = (T == OptimumTime ? 1 : MaxRatio);
+    const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
+
+    double thisMoveImportance = (move_importance(currentPly) * slowMover) / 100;
+    double otherMovesImportance = 0;
+
+    for (int i = 1; i < movesToGo; ++i)
+        otherMovesImportance += move_importance(currentPly + 2 * i);
+
+    double ratio1 = (TMaxRatio * thisMoveImportance) / (TMaxRatio * thisMoveImportance + otherMovesImportance);
+    double ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / (thisMoveImportance + otherMovesImportance);
+
+    return int(myTime * std::min(ratio1, ratio2));
+  }
+
+} // namespace
+
+
+void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color us)
+{
+  /* We support four different kinds of time controls:
+
+      increment == 0 && movesToGo == 0 means: x basetime  [sudden death!]
+      increment == 0 && movesToGo != 0 means: x moves in y minutes
+      increment >  0 && movesToGo == 0 means: x basetime + z increment
+      increment >  0 && movesToGo != 0 means: x moves in y minutes + z increment
+
+    Time management is adjusted by following UCI parameters:
+
+      emergencyMoveHorizon: Be prepared to always play at least this many moves
+      emergencyBaseTime   : Always attempt to keep at least this much time (in ms) at clock
+      emergencyMoveTime   : Plus attempt to keep at least this much time for each remaining emergency move
+      minThinkingTime     : No matter what, use at least this much thinking before doing the move
+  */
+
+  int hypMTG, hypMyTime, t1, t2;
+
+  // Read uci parameters
+  int emergencyMoveHorizon = Options["Emergency Move Horizon"];
+  int emergencyBaseTime    = Options["Emergency Base Time"];
+  int emergencyMoveTime    = Options["Emergency Move Time"];
+  int minThinkingTime      = Options["Minimum Thinking Time"];
+  int slowMover            = Options["Slow Mover"];
+
+  // Initialize unstablePvFactor to 1 and search times to maximum values
+  unstablePvFactor = 1;
+  optimumSearchTime = maximumSearchTime = std::max(limits.time[us], minThinkingTime);
+
+  // We calculate optimum time usage for different hypothetical "moves to go"-values and choose the
+  // minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
+  for (hypMTG = 1; hypMTG <= (limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon); ++hypMTG)
+  {
+      // Calculate thinking time for hypothetical "moves to go"-value
+      hypMyTime =  limits.time[us]
+                 + limits.inc[us] * (hypMTG - 1)
+                 - emergencyBaseTime
+                 - emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon);
+
+      hypMyTime = std::max(hypMyTime, 0);
+
+      t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly, slowMover);
+      t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly, slowMover);
+
+      optimumSearchTime = std::min(optimumSearchTime, t1);
+      maximumSearchTime = std::min(maximumSearchTime, t2);
+  }
+
+  if (Options["Ponder"])
+      optimumSearchTime += optimumSearchTime / 4;
+
+  // Make sure that maxSearchTime is not over absoluteMaxSearchTime
+  optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime);
+}
diff --git a/src/timeman.h b/src/timeman.h
new file mode 100644 (file)
index 0000000..a15551a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TIMEMAN_H_INCLUDED
+#define TIMEMAN_H_INCLUDED
+
+/// The TimeManager class computes the optimal time to think depending on the
+/// maximum available time, the game move number and other parameters.
+
+class TimeManager {
+public:
+  void init(const Search::LimitsType& limits, int currentPly, Color us);
+  void pv_instability(double bestMoveChanges) { unstablePvFactor = 1 + bestMoveChanges; }
+  int available_time() const { return int(optimumSearchTime * unstablePvFactor * 0.71); }
+  int maximum_time() const { return maximumSearchTime; }
+
+private:
+  int optimumSearchTime;
+  int maximumSearchTime;
+  double unstablePvFactor;
+};
+
+#endif // #ifndef TIMEMAN_H_INCLUDED
diff --git a/src/tt.cpp b/src/tt.cpp
new file mode 100644 (file)
index 0000000..248cbad
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cstring>
+#include <iostream>
+
+#include "bitboard.h"
+#include "tt.h"
+
+TranspositionTable TT; // Our global transposition table
+
+
+/// TranspositionTable::resize() sets the size of the transposition table,
+/// measured in megabytes. Transposition table consists of a power of 2 number
+/// of clusters and each cluster consists of TTClusterSize number of TTEntry.
+
+void TranspositionTable::resize(uint64_t mbSize) {
+
+  assert(msb((mbSize * 1024 * 1024) / sizeof(TTCluster)) < 32);
+
+  uint32_t newClusterCount = 1 << msb((mbSize * 1024 * 1024) / sizeof(TTCluster));
+
+  if (newClusterCount == clusterCount)
+      return;
+
+  clusterCount = newClusterCount;
+
+  free(mem);
+  mem = calloc(clusterCount * sizeof(TTCluster) + CACHE_LINE_SIZE - 1, 1);
+
+  if (!mem)
+  {
+      std::cerr << "Failed to allocate " << mbSize
+                << "MB for transposition table." << std::endl;
+      exit(EXIT_FAILURE);
+  }
+
+  table = (TTCluster*)((uintptr_t(mem) + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1));
+}
+
+
+/// TranspositionTable::clear() overwrites the entire transposition table
+/// with zeroes. It is called whenever the table is resized, or when the
+/// user asks the program to clear the table (from the UCI interface).
+
+void TranspositionTable::clear() {
+
+  std::memset(table, 0, clusterCount * sizeof(TTCluster));
+}
+
+
+/// TranspositionTable::probe() looks up the current position in the
+/// transposition table. Returns a pointer to the TTEntry or NULL if
+/// position is not found.
+
+const TTEntry* TranspositionTable::probe(const Key key) const {
+
+  TTEntry* tte = first_entry(key);
+  uint16_t key16 = key >> 48;
+
+  for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
+      if (tte->key16 == key16)
+      {
+          tte->genBound8 = generation | tte->bound(); // Refresh
+          return tte;
+      }
+
+  return NULL;
+}
+
+
+/// TranspositionTable::store() writes a new entry containing position key and
+/// valuable information of current position. The lowest order bits of position
+/// key are used to decide in which cluster the position will be placed.
+/// When a new entry is written and there are no empty entries available in the
+/// cluster, it replaces the least valuable of the entries. A TTEntry t1 is considered
+/// to be more valuable than a TTEntry t2 if t1 is from the current search and t2
+/// is from a previous search, or if the depth of t1 is bigger than the depth of t2.
+
+void TranspositionTable::store(const Key key, Value v, Bound b, Depth d, Move m, Value statV) {
+
+  TTEntry *tte, *replace;
+  uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster
+
+  tte = replace = first_entry(key);
+
+  for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
+  {
+      if (!tte->key16 || tte->key16 == key16) // Empty or overwrite old
+      {
+          if (!m)
+              m = tte->move(); // Preserve any existing ttMove
+
+          replace = tte;
+          break;
+      }
+
+      // Implement replace strategy
+      if (  ((    tte->genBound8 & 0xFC) == generation || tte->bound() == BOUND_EXACT)
+          - ((replace->genBound8 & 0xFC) == generation)
+          - (tte->depth8 < replace->depth8) < 0)
+          replace = tte;
+  }
+
+  replace->save(key16, v, b, d, m, generation, statV);
+}
diff --git a/src/tt.h b/src/tt.h
new file mode 100644 (file)
index 0000000..16523b3
--- /dev/null
+++ b/src/tt.h
@@ -0,0 +1,114 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TT_H_INCLUDED
+#define TT_H_INCLUDED
+
+#include "misc.h"
+#include "types.h"
+
+/// The TTEntry is the 10 bytes transposition table entry, defined as below:
+///
+/// key        16 bit
+/// move       16 bit
+/// value      16 bit
+/// eval value 16 bit
+/// generation  6 bit
+/// bound type  2 bit
+/// depth       8 bit
+
+struct TTEntry {
+
+  Move  move()  const      { return (Move )move16; }
+  Value value() const      { return (Value)value16; }
+  Value eval_value() const { return (Value)evalValue; }
+  Depth depth() const      { return (Depth)(depth8) + DEPTH_NONE; }
+  Bound bound() const      { return (Bound)(genBound8 & 0x3); }
+
+private:
+  friend class TranspositionTable;
+
+  void save(uint16_t k, Value v, Bound b, Depth d, Move m, uint8_t g, Value ev) {
+
+    key16     = (uint16_t)k;
+    move16    = (uint16_t)m;
+    value16   = (int16_t)v;
+    evalValue = (int16_t)ev;
+    genBound8 = (uint8_t)(g | b);
+    depth8    = (uint8_t)(d - DEPTH_NONE);
+  }
+
+  uint16_t key16;
+  uint16_t move16;
+  int16_t  value16;
+  int16_t  evalValue;
+  uint8_t  genBound8;
+  uint8_t  depth8;
+};
+
+/// TTCluster is a 32 bytes cluster of TT entries consisting of:
+///
+/// 3 x TTEntry (3 x 10 bytes)
+/// padding     (2 bytes)
+
+const unsigned TTClusterSize = 3;
+
+struct TTCluster {
+  TTEntry entry[TTClusterSize];
+  char padding[2];
+};
+
+/// A TranspositionTable consists of a power of 2 number of clusters and each
+/// cluster consists of TTClusterSize number of TTEntry. Each non-empty entry
+/// contains information of exactly one position. The size of a cluster should
+/// not be bigger than a cache line size. In case it is less, it should be padded
+/// to guarantee always aligned accesses.
+
+class TranspositionTable {
+
+public:
+ ~TranspositionTable() { free(mem); }
+  void new_search() { generation += 4; } // Lower 2 bits are used by Bound
+
+  const TTEntry* probe(const Key key) const;
+  TTEntry* first_entry(const Key key) const;
+  void resize(uint64_t mbSize);
+  void clear();
+  void store(const Key key, Value v, Bound type, Depth d, Move m, Value statV);
+
+private:
+  uint32_t clusterCount;
+  TTCluster* table;
+  void* mem;
+  uint8_t generation; // Size must be not bigger than TTEntry::genBound8
+};
+
+extern TranspositionTable TT;
+
+
+/// TranspositionTable::first_entry() returns a pointer to the first entry of
+/// a cluster given a position. The lowest order bits of the key are used to
+/// get the index of the cluster inside the table.
+
+inline TTEntry* TranspositionTable::first_entry(const Key key) const {
+
+  return &table[(uint32_t)key & (clusterCount - 1)].entry[0];
+}
+
+#endif // #ifndef TT_H_INCLUDED
diff --git a/src/types.h b/src/types.h
new file mode 100644 (file)
index 0000000..f921f9e
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TYPES_H_INCLUDED
+#define TYPES_H_INCLUDED
+
+/// For Linux and OSX configuration is done automatically using Makefile. To get
+/// started type 'make help'.
+///
+/// For Windows, part of the configuration is detected automatically, but some
+/// switches need to be set manually:
+///
+/// -DNDEBUG      | Disable debugging mode. Always use this.
+///
+/// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want
+///               | the executable to run on some very old machines.
+///
+/// -DUSE_POPCNT  | Add runtime support for use of popcnt asm-instruction. Works
+///               | only in 64-bit mode. For compiling requires hardware with
+///               | popcnt support.
+
+#include <cassert>
+#include <cctype>
+#include <climits>
+#include <cstdlib>
+
+#include "platform.h"
+
+#define unlikely(x) (x) // For code annotation purposes
+
+#if defined(_WIN64) && !defined(IS_64BIT)
+#  include <intrin.h> // MSVC popcnt and bsfq instrinsics
+#  define IS_64BIT
+#  define USE_BSFQ
+#endif
+
+#if defined(USE_POPCNT) && defined(_MSC_VER) && defined(__INTEL_COMPILER)
+#  include <nmmintrin.h> // Intel header for _mm_popcnt_u64() intrinsic
+#endif
+
+#if defined(USE_PEXT)
+#  include <immintrin.h> // Header for _pext_u64() intrinsic
+#else
+#  define _pext_u64(b, m) (0)
+#endif
+
+#  if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
+#   include <xmmintrin.h> // Intel and Microsoft header for _mm_prefetch()
+#  endif
+
+#define CACHE_LINE_SIZE 64
+#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#  define CACHE_LINE_ALIGNMENT __declspec(align(CACHE_LINE_SIZE))
+#else
+#  define CACHE_LINE_ALIGNMENT  __attribute__ ((aligned(CACHE_LINE_SIZE)))
+#endif
+
+#ifdef _MSC_VER
+#  define FORCE_INLINE  __forceinline
+#elif defined(__GNUC__)
+#  define FORCE_INLINE  inline __attribute__((always_inline))
+#else
+#  define FORCE_INLINE  inline
+#endif
+
+#ifdef USE_POPCNT
+const bool HasPopCnt = true;
+#else
+const bool HasPopCnt = false;
+#endif
+
+#ifdef USE_PEXT
+const bool HasPext = true;
+#else
+const bool HasPext = false;
+#endif
+
+#ifdef IS_64BIT
+const bool Is64Bit = true;
+#else
+const bool Is64Bit = false;
+#endif
+
+typedef uint64_t Key;
+typedef uint64_t Bitboard;
+
+const int MAX_MOVES      = 256;
+const int MAX_PLY        = 120;
+const int MAX_PLY_PLUS_6 = MAX_PLY + 6;
+
+/// A move needs 16 bits to be stored
+///
+/// bit  0- 5: destination square (from 0 to 63)
+/// bit  6-11: origin square (from 0 to 63)
+/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
+/// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
+/// NOTE: EN-PASSANT bit is set only when a pawn can be captured
+///
+/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
+/// any normal move destination square is always different from origin square
+/// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
+
+enum Move {
+  MOVE_NONE,
+  MOVE_NULL = 65
+};
+
+enum MoveType {
+  NORMAL,
+  PROMOTION = 1 << 14,
+  ENPASSANT = 2 << 14,
+  CASTLING  = 3 << 14
+};
+
+enum Color {
+  WHITE, BLACK, NO_COLOR, COLOR_NB = 2
+};
+
+enum CastlingSide {
+  KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2
+};
+
+enum CastlingRight {
+  NO_CASTLING,
+  WHITE_OO,
+  WHITE_OOO   = WHITE_OO << 1,
+  BLACK_OO    = WHITE_OO << 2,
+  BLACK_OOO   = WHITE_OO << 3,
+  ANY_CASTLING = WHITE_OO | WHITE_OOO | BLACK_OO | BLACK_OOO,
+  CASTLING_RIGHT_NB = 16
+};
+
+template<Color C, CastlingSide S> struct MakeCastling {
+  static const CastlingRight
+  right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
+                     : S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
+};
+
+enum Phase {
+  PHASE_ENDGAME,
+  PHASE_MIDGAME = 128,
+  MG = 0, EG = 1, PHASE_NB = 2
+};
+
+enum ScaleFactor {
+  SCALE_FACTOR_DRAW    = 0,
+  SCALE_FACTOR_ONEPAWN = 48,
+  SCALE_FACTOR_NORMAL  = 64,
+  SCALE_FACTOR_MAX     = 128,
+  SCALE_FACTOR_NONE    = 255
+};
+
+enum Bound {
+  BOUND_NONE,
+  BOUND_UPPER,
+  BOUND_LOWER,
+  BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
+};
+
+enum Value {
+  VALUE_ZERO      = 0,
+  VALUE_DRAW      = 0,
+  VALUE_KNOWN_WIN = 10000,
+  VALUE_MATE      = 32000,
+  VALUE_INFINITE  = 32001,
+  VALUE_NONE      = 32002,
+
+  VALUE_MATE_IN_MAX_PLY  =  VALUE_MATE - MAX_PLY,
+  VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY,
+
+  VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX,
+  VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN,
+
+  PawnValueMg   = 198,   PawnValueEg   = 258,
+  KnightValueMg = 817,   KnightValueEg = 846,
+  BishopValueMg = 836,   BishopValueEg = 857,
+  RookValueMg   = 1270,  RookValueEg   = 1278,
+  QueenValueMg  = 2521,  QueenValueEg  = 2558,
+
+  MidgameLimit  = 15581, EndgameLimit  = 3998
+};
+
+enum PieceType {
+  NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
+  ALL_PIECES = 0,
+  PIECE_TYPE_NB = 8
+};
+
+enum Piece {
+  NO_PIECE,
+  W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
+  B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
+  PIECE_NB = 16
+};
+
+enum Depth {
+
+  ONE_PLY = 2,
+
+  DEPTH_ZERO          =  0 * ONE_PLY,
+  DEPTH_QS_CHECKS     =  0 * ONE_PLY,
+  DEPTH_QS_NO_CHECKS  = -1 * ONE_PLY,
+  DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
+
+  DEPTH_NONE = -6 * ONE_PLY
+};
+
+enum Square {
+  SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
+  SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
+  SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
+  SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
+  SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
+  SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
+  SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
+  SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
+  SQ_NONE,
+
+  SQUARE_NB = 64,
+
+  DELTA_N =  8,
+  DELTA_E =  1,
+  DELTA_S = -8,
+  DELTA_W = -1,
+
+  DELTA_NN = DELTA_N + DELTA_N,
+  DELTA_NE = DELTA_N + DELTA_E,
+  DELTA_SE = DELTA_S + DELTA_E,
+  DELTA_SS = DELTA_S + DELTA_S,
+  DELTA_SW = DELTA_S + DELTA_W,
+  DELTA_NW = DELTA_N + DELTA_W
+};
+
+enum File {
+  FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
+};
+
+enum Rank {
+  RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
+};
+
+
+/// The Score enum stores a middlegame and an endgame value in a single integer
+/// (enum). The least significant 16 bits are used to store the endgame value
+/// and the upper 16 bits are used to store the middlegame value. The compiler
+/// is free to choose the enum type as long as it can store the data, so we
+/// ensure that Score is an integer type by assigning some big int values.
+enum Score {
+  SCORE_ZERO,
+  SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX,
+  SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN
+};
+
+inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
+
+/// Extracting the signed lower and upper 16 bits is not so trivial because
+/// according to the standard a simple cast to short is implementation defined
+/// and so is a right shift of a signed integer.
+inline Value mg_value(Score s) {
+  return Value(((s + 0x8000) & ~0xffff) / 0x10000);
+}
+
+inline Value eg_value(Score s) {
+  return Value((int)(unsigned(s) & 0x7FFFU) - (int)(unsigned(s) & 0x8000U));
+}
+
+#define ENABLE_BASE_OPERATORS_ON(T)                                         \
+inline T operator+(const T d1, const T d2) { return T(int(d1) + int(d2)); } \
+inline T operator-(const T d1, const T d2) { return T(int(d1) - int(d2)); } \
+inline T operator*(int i, const T d) { return T(i * int(d)); }              \
+inline T operator*(const T d, int i) { return T(int(d) * i); }              \
+inline T operator-(const T d) { return T(-int(d)); }                        \
+inline T& operator+=(T& d1, const T d2) { return d1 = d1 + d2; }            \
+inline T& operator-=(T& d1, const T d2) { return d1 = d1 - d2; }            \
+inline T& operator*=(T& d, int i) { return d = T(int(d) * i); }
+
+ENABLE_BASE_OPERATORS_ON(Score)
+
+#define ENABLE_FULL_OPERATORS_ON(T)                                         \
+ENABLE_BASE_OPERATORS_ON(T)                                                 \
+inline T& operator++(T& d) { return d = T(int(d) + 1); }                    \
+inline T& operator--(T& d) { return d = T(int(d) - 1); }                    \
+inline T operator/(const T d, int i) { return T(int(d) / i); }              \
+inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
+
+ENABLE_FULL_OPERATORS_ON(Value)
+ENABLE_FULL_OPERATORS_ON(PieceType)
+ENABLE_FULL_OPERATORS_ON(Piece)
+ENABLE_FULL_OPERATORS_ON(Color)
+ENABLE_FULL_OPERATORS_ON(Depth)
+ENABLE_FULL_OPERATORS_ON(Square)
+ENABLE_FULL_OPERATORS_ON(File)
+ENABLE_FULL_OPERATORS_ON(Rank)
+
+#undef ENABLE_FULL_OPERATORS_ON
+#undef ENABLE_BASE_OPERATORS_ON
+
+/// Additional operators to add integers to a Value
+inline Value operator+(Value v, int i) { return Value(int(v) + i); }
+inline Value operator-(Value v, int i) { return Value(int(v) - i); }
+inline Value& operator+=(Value& v, int i) { return v = v + i; }
+inline Value& operator-=(Value& v, int i) { return v = v - i; }
+
+/// Only declared but not defined. We don't want to multiply two scores due to
+/// a very high risk of overflow. So user should explicitly convert to integer.
+inline Score operator*(Score s1, Score s2);
+
+/// Division of a Score must be handled separately for each term
+inline Score operator/(Score s, int i) {
+  return make_score(mg_value(s) / i, eg_value(s) / i);
+}
+
+CACHE_LINE_ALIGNMENT
+
+extern Value PieceValue[PHASE_NB][PIECE_NB];
+
+struct ExtMove {
+  Move move;
+  Value value;
+};
+
+inline bool operator<(const ExtMove& f, const ExtMove& s) {
+  return f.value < s.value;
+}
+
+inline Color operator~(Color c) {
+  return Color(c ^ BLACK);
+}
+
+inline Square operator~(Square s) {
+  return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
+}
+
+inline CastlingRight operator|(Color c, CastlingSide s) {
+  return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
+}
+
+inline Value mate_in(int ply) {
+  return VALUE_MATE - ply;
+}
+
+inline Value mated_in(int ply) {
+  return -VALUE_MATE + ply;
+}
+
+inline Square make_square(File f, Rank r) {
+  return Square((r << 3) | f);
+}
+
+inline Piece make_piece(Color c, PieceType pt) {
+  return Piece((c << 3) | pt);
+}
+
+inline PieceType type_of(Piece pc)  {
+  return PieceType(pc & 7);
+}
+
+inline Color color_of(Piece pc) {
+  assert(pc != NO_PIECE);
+  return Color(pc >> 3);
+}
+
+inline bool is_ok(Square s) {
+  return s >= SQ_A1 && s <= SQ_H8;
+}
+
+inline File file_of(Square s) {
+  return File(s & 7);
+}
+
+inline Rank rank_of(Square s) {
+  return Rank(s >> 3);
+}
+
+inline Square relative_square(Color c, Square s) {
+  return Square(s ^ (c * 56));
+}
+
+inline Rank relative_rank(Color c, Rank r) {
+  return Rank(r ^ (c * 7));
+}
+
+inline Rank relative_rank(Color c, Square s) {
+  return relative_rank(c, rank_of(s));
+}
+
+inline bool opposite_colors(Square s1, Square s2) {
+  int s = int(s1) ^ int(s2);
+  return ((s >> 3) ^ s) & 1;
+}
+
+inline Square pawn_push(Color c) {
+  return c == WHITE ? DELTA_N : DELTA_S;
+}
+
+inline Square from_sq(Move m) {
+  return Square((m >> 6) & 0x3F);
+}
+
+inline Square to_sq(Move m) {
+  return Square(m & 0x3F);
+}
+
+inline MoveType type_of(Move m) {
+  return MoveType(m & (3 << 14));
+}
+
+inline PieceType promotion_type(Move m) {
+  return PieceType(((m >> 12) & 3) + 2);
+}
+
+inline Move make_move(Square from, Square to) {
+  return Move(to | (from << 6));
+}
+
+template<MoveType T>
+inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
+  return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12));
+}
+
+inline bool is_ok(Move m) {
+  return from_sq(m) != to_sq(m); // Catches also MOVE_NULL and MOVE_NONE
+}
+
+#endif // #ifndef TYPES_H_INCLUDED
diff --git a/src/uci.cpp b/src/uci.cpp
new file mode 100644 (file)
index 0000000..6027295
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "evaluate.h"
+#include "notation.h"
+#include "position.h"
+#include "search.h"
+#include "thread.h"
+#include "tt.h"
+#include "ucioption.h"
+
+using namespace std;
+
+extern void benchmark(const Position& pos, istream& is);
+
+namespace {
+
+  // FEN string of the initial position, normal chess
+  const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+
+  // Keep a track of the position keys along the setup moves (from the start position
+  // to the position just before the search starts). This is needed by the repetition
+  // draw detection code.
+  Search::StateStackPtr SetupStates;
+
+
+  // position() is called when engine receives the "position" UCI command.
+  // The function sets up the position described in the given FEN string ("fen")
+  // or the starting position ("startpos") and then makes the moves given in the
+  // following move list ("moves").
+
+  void position(Position& pos, istringstream& is) {
+
+    Move m;
+    string token, fen;
+
+    is >> token;
+
+    if (token == "startpos")
+    {
+        fen = StartFEN;
+        is >> token; // Consume "moves" token if any
+    }
+    else if (token == "fen")
+        while (is >> token && token != "moves")
+            fen += token + " ";
+    else
+        return;
+
+    pos.set(fen, Options["UCI_Chess960"], Threads.main());
+    SetupStates = Search::StateStackPtr(new std::stack<StateInfo>());
+
+    // Parse move list (if any)
+    while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE)
+    {
+        SetupStates->push(StateInfo());
+        pos.do_move(m, SetupStates->top());
+    }
+  }
+
+
+  // setoption() is called when engine receives the "setoption" UCI command. The
+  // function updates the UCI option ("name") to the given value ("value").
+
+  void setoption(istringstream& is) {
+
+    string token, name, value;
+
+    is >> token; // Consume "name" token
+
+    // Read option name (can contain spaces)
+    while (is >> token && token != "value")
+        name += string(" ", !name.empty()) + token;
+
+    // Read option value (can contain spaces)
+    while (is >> token)
+        value += string(" ", !value.empty()) + token;
+
+    if (Options.count(name))
+        Options[name] = value;
+    else
+        sync_cout << "No such option: " << name << sync_endl;
+  }
+
+
+  // go() is called when engine receives the "go" UCI command. The function sets
+  // the thinking time and other parameters from the input string, and starts
+  // the search.
+
+  void go(const Position& pos, istringstream& is) {
+
+    Search::LimitsType limits;
+    string token;
+
+    while (is >> token)
+    {
+        if (token == "searchmoves")
+            while (is >> token)
+                limits.searchmoves.push_back(move_from_uci(pos, token));
+
+        else if (token == "wtime")     is >> limits.time[WHITE];
+        else if (token == "btime")     is >> limits.time[BLACK];
+        else if (token == "winc")      is >> limits.inc[WHITE];
+        else if (token == "binc")      is >> limits.inc[BLACK];
+        else if (token == "movestogo") is >> limits.movestogo;
+        else if (token == "depth")     is >> limits.depth;
+        else if (token == "nodes")     is >> limits.nodes;
+        else if (token == "movetime")  is >> limits.movetime;
+        else if (token == "mate")      is >> limits.mate;
+        else if (token == "infinite")  limits.infinite = true;
+        else if (token == "ponder")    limits.ponder = true;
+    }
+
+    Threads.start_thinking(pos, limits, SetupStates);
+  }
+
+} // namespace
+
+
+/// Wait for a command from the user, parse this text string as an UCI command,
+/// and call the appropriate functions. Also intercepts EOF from stdin to ensure
+/// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI
+/// commands, the function also supports a few debug commands.
+
+void UCI::loop(int argc, char* argv[]) {
+
+  Position pos(StartFEN, false, Threads.main()); // The root position
+  string token, cmd;
+
+  for (int i = 1; i < argc; ++i)
+      cmd += std::string(argv[i]) + " ";
+
+  do {
+      if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input
+          cmd = "quit";
+
+      istringstream is(cmd);
+
+      is >> skipws >> token;
+
+      if (token == "quit" || token == "stop" || token == "ponderhit")
+      {
+          // The GUI sends 'ponderhit' to tell us to ponder on the same move the
+          // opponent has played. In case Signals.stopOnPonderhit is set we are
+          // waiting for 'ponderhit' to stop the search (for instance because we
+          // already ran out of time), otherwise we should continue searching but
+          // switch from pondering to normal search.
+          if (token != "ponderhit" || Search::Signals.stopOnPonderhit)
+          {
+              Search::Signals.stop = true;
+              Threads.main()->notify_one(); // Could be sleeping
+          }
+          else
+              Search::Limits.ponder = false;
+      }
+      else if (token == "perft")
+      {
+          int depth;
+          stringstream ss;
+
+          is >> depth;
+          ss << Options["Hash"]    << " "
+             << Options["Threads"] << " " << depth << " current " << token;
+
+          benchmark(pos, ss);
+      }
+      else if (token == "key")
+          sync_cout << hex << uppercase << setfill('0')
+                    << "position key: "   << setw(16) << pos.key()
+                    << "\nmaterial key: " << setw(16) << pos.material_key()
+                    << "\npawn key:     " << setw(16) << pos.pawn_key()
+                    << dec << nouppercase << setfill(' ') << sync_endl;
+
+      else if (token == "uci")
+          sync_cout << "id name " << engine_info(true)
+                    << "\n"       << Options
+                    << "\nuciok"  << sync_endl;
+
+      else if (token == "ucinewgame") TT.clear();
+      else if (token == "go")         go(pos, is);
+      else if (token == "position")   position(pos, is);
+      else if (token == "setoption")  setoption(is);
+      else if (token == "flip")       pos.flip();
+      else if (token == "bench")      benchmark(pos, is);
+      else if (token == "d")          sync_cout << pos.pretty() << sync_endl;
+      else if (token == "isready")    sync_cout << "readyok" << sync_endl;
+      else if (token == "eval")       sync_cout << Eval::trace(pos) << sync_endl;
+      else
+          sync_cout << "Unknown command: " << cmd << sync_endl;
+
+  } while (token != "quit" && argc == 1); // Passed args have one-shot behaviour
+
+  Threads.wait_for_think_finished(); // Cannot quit whilst the search is running
+}
diff --git a/src/ucioption.cpp b/src/ucioption.cpp
new file mode 100644 (file)
index 0000000..434a5b2
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <sstream>
+
+#include "evaluate.h"
+#include "misc.h"
+#include "thread.h"
+#include "tt.h"
+#include "ucioption.h"
+
+using std::string;
+
+UCI::OptionsMap Options; // Global object
+
+namespace UCI {
+
+/// 'On change' actions, triggered by an option's value change
+void on_logger(const Option& o) { start_logger(o); }
+void on_eval(const Option&) { Eval::init(); }
+void on_threads(const Option&) { Threads.read_uci_options(); }
+void on_hash_size(const Option& o) { TT.resize(o); }
+void on_clear_hash(const Option&) { TT.clear(); }
+
+
+/// Our case insensitive less() function as required by UCI protocol
+bool ci_less(char c1, char c2) { return tolower(c1) < tolower(c2); }
+
+bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
+  return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), ci_less);
+}
+
+
+/// init() initializes the UCI options to their hard-coded default values
+
+void init(OptionsMap& o) {
+
+  o["Write Debug Log"]          << Option(false, on_logger);
+  o["Write Search Log"]         << Option(false);
+  o["Search Log Filename"]      << Option("SearchLog.txt");
+  o["Contempt Factor"]          << Option(0, -50,  50);
+  o["Min Split Depth"]          << Option(0, 0, 12, on_threads);
+  o["Threads"]                  << Option(1, 1, MAX_THREADS, on_threads);
+  o["Hash"]                     << Option(16, 1, 65536, on_hash_size);
+  o["Clear Hash"]               << Option(on_clear_hash);
+  o["Ponder"]                   << Option(true);
+  o["MultiPV"]                  << Option(1, 1, 500);
+  o["Skill Level"]              << Option(20, 0, 20);
+  o["Emergency Move Horizon"]   << Option(40, 0, 50);
+  o["Emergency Base Time"]      << Option(60, 0, 30000);
+  o["Emergency Move Time"]      << Option(30, 0, 5000);
+  o["Minimum Thinking Time"]    << Option(20, 0, 5000);
+  o["Slow Mover"]               << Option(80, 10, 1000);
+  o["UCI_Chess960"]             << Option(false);
+}
+
+
+/// operator<<() is used to print all the options default values in chronological
+/// insertion order (the idx field) and in the format defined by the UCI protocol.
+
+std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
+
+  for (size_t idx = 0; idx < om.size(); ++idx)
+      for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it)
+          if (it->second.idx == idx)
+          {
+              const Option& o = it->second;
+              os << "\noption name " << it->first << " type " << o.type;
+
+              if (o.type != "button")
+                  os << " default " << o.defaultValue;
+
+              if (o.type == "spin")
+                  os << " min " << o.min << " max " << o.max;
+
+              break;
+          }
+  return os;
+}
+
+
+/// Option class constructors and conversion operators
+
+Option::Option(const char* v, OnChange f) : type("string"), min(0), max(0), on_change(f)
+{ defaultValue = currentValue = v; }
+
+Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f)
+{ defaultValue = currentValue = (v ? "true" : "false"); }
+
+Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f)
+{}
+
+Option::Option(int v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f)
+{ std::ostringstream ss; ss << v; defaultValue = currentValue = ss.str(); }
+
+
+Option::operator int() const {
+  assert(type == "check" || type == "spin");
+  return (type == "spin" ? atoi(currentValue.c_str()) : currentValue == "true");
+}
+
+Option::operator std::string() const {
+  assert(type == "string");
+  return currentValue;
+}
+
+
+/// operator<<() inits options and assigns idx in the correct printing order
+
+void Option::operator<<(const Option& o) {
+
+  static size_t insert_order = 0;
+
+  *this = o;
+  idx = insert_order++;
+}
+
+
+/// operator=() updates currentValue and triggers on_change() action. It's up to
+/// the GUI to check for option's limits, but we could receive the new value from
+/// the user by console window, so let's check the bounds anyway.
+
+Option& Option::operator=(const string& v) {
+
+  assert(!type.empty());
+
+  if (   (type != "button" && v.empty())
+      || (type == "check" && v != "true" && v != "false")
+      || (type == "spin" && (atoi(v.c_str()) < min || atoi(v.c_str()) > max)))
+      return *this;
+
+  if (type != "button")
+      currentValue = v;
+
+  if (on_change)
+      on_change(*this);
+
+  return *this;
+}
+
+} // namespace UCI
diff --git a/src/ucioption.h b/src/ucioption.h
new file mode 100644 (file)
index 0000000..87411a4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
+
+  Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef UCIOPTION_H_INCLUDED
+#define UCIOPTION_H_INCLUDED
+
+#include <map>
+#include <string>
+
+namespace UCI {
+
+class Option;
+
+/// Custom comparator because UCI options should be case insensitive
+struct CaseInsensitiveLess {
+  bool operator() (const std::string&, const std::string&) const;
+};
+
+/// Our options container is actually a std::map
+typedef std::map<std::string, Option, CaseInsensitiveLess> OptionsMap;
+
+/// Option class implements an option as defined by UCI protocol
+class Option {
+
+  typedef void (*OnChange)(const Option&);
+
+public:
+  Option(OnChange = NULL);
+  Option(bool v, OnChange = NULL);
+  Option(const char* v, OnChange = NULL);
+  Option(int v, int min, int max, OnChange = NULL);
+
+  Option& operator=(const std::string& v);
+  void operator<<(const Option& o);
+  operator int() const;
+  operator std::string() const;
+
+private:
+  friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
+
+  std::string defaultValue, currentValue, type;
+  int min, max;
+  size_t idx;
+  OnChange on_change;
+};
+
+void init(OptionsMap&);
+void loop(int argc, char* argv[]);
+
+} // namespace UCI
+
+extern UCI::OptionsMap Options;
+
+#endif // #ifndef UCIOPTION_H_INCLUDED