Initial import of Glaurung 2.1
authorMarco Costalba <mcostalba@gmail.com>
Mon, 1 Sep 2008 05:59:13 +0000 (07:59 +0200)
committerMarco Costalba <mcostalba@gmail.com>
Mon, 1 Sep 2008 05:59:13 +0000 (07:59 +0200)
64 files changed:
Copying.txt [new file with mode: 0644]
Readme.txt [new file with mode: 0644]
polyglot.ini [new file with mode: 0644]
src/COPYING [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/benchmark.cpp [new file with mode: 0644]
src/benchmark.h [new file with mode: 0644]
src/bitbase.cpp [new file with mode: 0644]
src/bitbase.h [new file with mode: 0644]
src/bitboard.cpp [new file with mode: 0644]
src/bitboard.h [new file with mode: 0644]
src/book.cpp [new file with mode: 0644]
src/book.h [new file with mode: 0644]
src/color.cpp [new file with mode: 0644]
src/color.h [new file with mode: 0644]
src/depth.h [new file with mode: 0644]
src/direction.cpp [new file with mode: 0644]
src/direction.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/history.cpp [new file with mode: 0644]
src/history.h [new file with mode: 0644]
src/lock.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/mersenne.cpp [new file with mode: 0644]
src/mersenne.h [new file with mode: 0644]
src/misc.cpp [new file with mode: 0644]
src/misc.h [new file with mode: 0644]
src/move.cpp [new file with mode: 0644]
src/move.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/pawns.cpp [new file with mode: 0644]
src/pawns.h [new file with mode: 0644]
src/phase.h [new file with mode: 0644]
src/piece.cpp [new file with mode: 0644]
src/piece.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/san.cpp [new file with mode: 0644]
src/san.h [new file with mode: 0644]
src/scale.h [new file with mode: 0644]
src/search.cpp [new file with mode: 0644]
src/search.h [new file with mode: 0644]
src/square.cpp [new file with mode: 0644]
src/square.h [new file with mode: 0644]
src/thread.h [new file with mode: 0644]
src/timeoday.cpp [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/uci.h [new file with mode: 0644]
src/ucioption.cpp [new file with mode: 0644]
src/ucioption.h [new file with mode: 0644]
src/value.cpp [new file with mode: 0644]
src/value.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.txt b/Readme.txt
new file mode 100644 (file)
index 0000000..defd2fc
--- /dev/null
@@ -0,0 +1,328 @@
+1. Introduction\r
+---------------\r
+\r
+Glaurung is a free UCI chess engine.  It is not a complete chess\r
+program, but requires some UCI compatible GUI (like XBoard with\r
+PolyGlot, eboard, José, Arena, Sigma Chess, Shredder, Chess Partner,\r
+or Fritz) in order to be used comfortably.  Read the documentation for\r
+your GUI of choice for information about how to use Glaurung with your\r
+GUI.\r
+\r
+Glaurung 2 is a completely rewritten version of Glaurung.  Apart from\r
+the parallel search code, almost no code is shared with Glaurung\r
+1.2.1, the previous stable version.  The new program is clearly\r
+stronger than the old, but has a less attractive style of play,\r
+because there are still a few major holes in its evaluation function\r
+(most notably space and development).\r
+\r
+This version of Glaurung supports up to 8 CPUs, but has not been\r
+tested thoroughly with more than 2.  The program tries to detect the\r
+number of CPUs on your computer and set the number of search threads\r
+accordingly, but please be aware that the detection is not always\r
+correct.  It is therefore recommended to inspect the value of the\r
+"Threads" UCI parameter, and to make sure it equals the number of CPU\r
+cores on your computer.\r
+\r
+\r
+2. Files\r
+--------\r
+\r
+This distribution of Glaurung consists of the following files:\r
+\r
+  * Readme.txt, the file you are currently reading.\r
+\r
+  * Copying.txt, a text file containing the GNU General Public\r
+    License.\r
+\r
+  * src/, a subdirectory containing the full source code, including a\r
+    Makefile that can be used to compile Glaurung on Unix-like\r
+    systems.  For further information about how to compile Glaurung\r
+    yourself, read section 4 below.\r
+\r
+  * MacOSX/, a subdirectory containing excutables for Apple Macintosh\r
+    computers running Mac OS X 10.4 (Tiger) and newer.  There are two\r
+    executables, one for OS X 10.4, and one for OS X 10.5.  The\r
+    executable for OS X 10.4 will work in 10.5 as well, but the one\r
+    for 10.5 is faster.\r
+\r
+  * LinuxX86/, a subdirectory containing 32-bit and 64-bit x86 GNU/Linux\r
+    executables.\r
+\r
+  * Windows/, a subdirectory containing 32-bit and 64-bit Windows\r
+    executables.\r
+\r
+  * polyglot.ini, for using Glaurung with Fabien Letouzey's PolyGlot\r
+    adapter.\r
+\r
+\r
+3. Opening books\r
+----------------\r
+\r
+This version of Glaurung has experimental support for PolyGlot opening\r
+books.  For information about how to create such books, consult the\r
+PolyGlot documentation.  The book file can be selected by setting the\r
+UCI parameter "Book File".\r
+\r
+A book file contributed by Salvo Spitaleri can be found on the\r
+Glaurung web page.\r
+\r
+\r
+4. Compiling it yourself\r
+------------------------\r
+\r
+On Unix-like systems, it should usually be possible to compile\r
+Glaurung directly from the source code with the included Makefile.\r
+The exception is computer with big-endian CPUs, like PowerPC\r
+Macintoshes.  Some of the bitboard routines in the current version of\r
+Glaurung are endianness-sensitive, and won't work on a big-endian CPU.\r
+Ensuring that the line with #define USE_32BIT_ATTACKS" near the top\r
+of bitboard.h is commented out should solve this problem.\r
+Commenting out the line with "#define USE_32BIT_ATTACKS" near the\r
+\r
+There is also a problem with compiling Glaurung on certain 64-bit \r
+systems, regardless of the endianness.  If Glaurung segfaults \r
+immediately after startup, try to comment out the line with \r
+"#define USE_FOLDED_BITSCAN" near the beginning of bitboard.h and\r
+recompile.\r
+\r
+Finally, even if Glaurung does work without any changes on your\r
+computer, it might be possible to improve the performance by changing\r
+some of the #define directives in bitboard.h.  The default settings\r
+are optimized for 64-bit CPUs.  On 32-bit CPUs, it is probably better\r
+to switch on USE_32BIT_ATTACKS, and to use BITCOUNT_SWAR_32 instead of\r
+BITCOUNT_SWAR_64.  For computers with very little memory (like\r
+handheld devices), it is possible to conserve memory by defining\r
+USE_COMPACT_ROOK_ATTACKS. \r
+\r
+\r
+\r
+5. History\r
+----------\r
+\r
+2007-05-06: Glaurung 2 - epsilon\r
+--------------------------------\r
+\r
+The first public release, and the first version of my new program\r
+which is able to match the old Glaurung 1.2.1 on a single CPU.  Lots\r
+of features and chess knowledge is still missing.\r
+\r
+2007-05-10: Glaurung 2 - epsilon/2\r
+----------------------------------\r
+\r
+This version is very close to 2 - epsilon.  The major changes are:\r
+\r
+  * A number of compatibility problems which appeared when trying to\r
+    compile Glaurung 2 - epsilon on various operating systems and CPUs\r
+    have been solved.\r
+\r
+  * Fixed a major bug in the detection of rooks trapped inside a\r
+    friendly king.\r
+\r
+  * Added knowledge about several types of drawn endgames.\r
+\r
+  * Fixed a few FRC related bugs.  FRC now works, but because of\r
+    serious holes in the evaluation function the program plays very\r
+    badly.\r
+\r
+  * A slightly more sophisticated king safety evaluation.\r
+\r
+2007-06-07: Glaurung 2 - epsilon/3\r
+----------------------------------\r
+\r
+The first public version with support for multiple CPUs.  Unless you\r
+have a dual-core (or better) computer, use Glaurung with a PolyGlot\r
+book, or runs games with ponder on, you may want to skip this version,\r
+which is almost certainly no stronger than 2 - epsilon/2 when running\r
+on a single CPU.  The main changes compared to the previous version\r
+are:\r
+\r
+  * Parallel search, with support for 1-4 CPUs.  The program currently\r
+    always allocates a separate pawn hash table and material hash\r
+    table for four threads, which is a pure waste of RAM if your\r
+    computer has just a single CPU.  This will be fixed in a future\r
+    version.\r
+\r
+  * Fixed a bug in book randomization.  When using Polyglot books, the\r
+    previous version would always select exactly the same move in the\r
+    same position after a restart of the program.  Thanks to Pavel\r
+    Háse for pointing this out.\r
+\r
+  * Fixed a UCI pondering bug: Glaurung no longer instantly prints its\r
+    best move when the maximum depth is reached during a ponder\r
+    search, as the previous version did.  According to the UCI\r
+    protocol, it is not allowed to print the best move before the\r
+    engine has received the "stop" or "quit" command.\r
+\r
+  * Additional search information:  The new version displays hash\r
+    saturation and the current line(s) of search.\r
+\r
+  * Several minor bug fixes and optimizations in the search and\r
+    evaluation. \r
+\r
+2007-06-08: Glaurung 2 - epsilon/4\r
+----------------------------------\r
+\r
+A bugfix release, with only a single important change:\r
+\r
+   * Fixed a very serious pondering bug.  As pointed out by Marc\r
+     Lacrosse, the previous version would lose on time in almost every\r
+     single game with pondering enabled.  The new version handles\r
+     pondering correctly (or so I hope).  When playing with ponder\r
+     off, the new version is identical to version 2 - epsilon/3.\r
+\r
+2007-06-25: Glaurung 2 - epsilon/5\r
+----------------------------------\r
+\r
+Another minor update, including the following improvements and bug\r
+fixes:\r
+\r
+   * As Werner Schüle discovered, the previous version would sometimes\r
+     stop thinking and lose on time right before delivering checkmate\r
+     (which is of course a very unfortunate moment to lose on time).\r
+     I haven't been able to reproduce Werner's problem on my computer\r
+     (probably because I run a different OS), but I have fixed the bug\r
+     which I suspect caused the time losses.  I hope the time losses\r
+     will no longer occur with 2 - epsilon/5.\r
+\r
+   * The program is now slightly less resource-hungry on computers\r
+     with less than 4 CPU cores: The previous version would always\r
+     allocated separate pawn and material hash tables for four\r
+     threads, even when running on a single-core CPU.  The new version\r
+     only allocates pawn and material hash tables for the threads\r
+     which are actually used.\r
+\r
+   * A minor reorganization of the memory layout has made the parallel\r
+     search about 10% more efficient (at least on my computer, but the\r
+     results are likely to vary considerably on different systems).\r
+\r
+   * The Intel Mac OS X binary is much faster than before, thanks to\r
+     the Intel C++ compiler (previous versions were compiled with\r
+     GCC).\r
+\r
+   * A few other very minor bug fixes and enhancements.\r
+\r
+2007-11-21: Glaurung 2.0\r
+------------------------\r
+\r
+The first stable (or so I hope) and feature-complete version of\r
+Glaurung 2.  The following are the main changes compared to the\r
+previous version:\r
+\r
+   * The license has been changed from GPL version 2 to GPL version 3.\r
+\r
+   * MultiPV mode.\r
+\r
+   * Support for the "searchmoves" option in the UCI "go" command.\r
+     This means that it is possible to ask Glaurung to exclude some\r
+     moves from its analysis, or to restrict its analysis to just a\r
+     handful of moves selected by the user.  This feature must also be\r
+     supported by the GUI under which Glaurung is run.  Glaurung's own\r
+     GUI does currently not support this feature.\r
+\r
+   * Chess960 support now works.  The program still plays this game \r
+     very badly, because of lack of opening knowledge.\r
+\r
+   * Much more aggressive pruning in the last few plies of the main\r
+     search.\r
+\r
+   * Somewhat better scaling on multi-CPU systems, and support for up\r
+     to 8 CPUs.\r
+\r
+   * Lots of new UCI parameters.\r
+\r
+   * Improved time managment, especially in games with pondering on \r
+     (i.e. when the engine is allowed to think when it's the\r
+     opponent's turn to move).\r
+\r
+   * Some evaluation improvements, and some new basic endgame\r
+     patterns.\r
+\r
+   * The program should no longer crash if the game lasts longer than\r
+     1000 plies.\r
\r
+   * Many minor bug fixes and other tiny improvements throughout the\r
+     code.  \r
\r
+   * More generously commented code, and numerous cosmetic changes in\r
+     coding style.\r
+\r
+2007-11-22: Glaurung 2.0.1\r
+--------------------------\r
+\r
+   * Fixed (or so I hope) a bug which would occasionally cause one of\r
+     the search threads to get stuck forever in its idle loop.\r
+\r
+2008-05-14: Glaurung 2.1\r
+------------------------\r
+\r
+This version contains far too many changes to list them all, but most\r
+of them are minor and cosmetic.  The most important and noticable\r
+changes are a lot of new UCI parameters, and many improvements in the\r
+evaluation function.  The highlights are:\r
+\r
+   * Extensive changes in the evaluation function.  The addition of\r
+     king safety is the most important improvement, but there are also\r
+     numerous little improvements elsewhere in the evaluation.  There\r
+     is still much work left to do in the evaluation function, though.\r
+     Space and development are still missing, and the tuning is likely\r
+     to be very poor.  Currently, the program is optimized for an\r
+     entertaining style rather than maximum strength.\r
+\r
+   * More accurate forward pruning.  The previous version used the\r
+     null move refutation move to improve the pruning accuracy by\r
+     means of a very simple trick: It did not allow pruning of any\r
+     moves with the piece captured by the null move refutation move.\r
+     In Glaurung 2.1, this has been enhanced: It does not allow\r
+     pruning of moves which defend the destination square of the null\r
+     move refutation move, nor of moves which block the ray of the\r
+     piece in the case that the moving piece in the null move\r
+     refutation move is a slider.\r
+\r
+   * More conservative use of LMR at PV nodes.  The previous version\r
+     searched the first 6 moves with full depth, 2.1 by default\r
+     searches the first 14 moves with full depth (but there is a new\r
+     UCI parameter for configuring this).  I am not at all sure\r
+     whether this is an improvement.  More thorough testing is\r
+     required. \r
+\r
+   * Feedback from the evaluation to the search.  The search passes an\r
+     object of type 'EvalInfo' to the eval, and the eval fills this\r
+     struct with various potentially useful information (like the sets\r
+     of squares attacked by each piece type, the middle game and\r
+     endgame components of the eval, etc.).  At the moment, almost\r
+     none of this information is actually used by the search.  The\r
+     only exception is that the evaluation function is now used to\r
+     adjust the futility pruning margin in the quiescence search.\r
+\r
+   * Less extensions.  This hurts the programs performance a lot in most\r
+     test suites, but I hope it improves the branching factor in deep\r
+     searches.\r
+\r
+   * A very long list of new UCI parameters, especially for tuning the\r
+     evaluation. \r
+\r
+\r
+6. Terms of use\r
+---------------\r
+\r
+Glaurung is free, and distributed under the GNU General Public License\r
+(GPL).  Essentially, this means that you are free to do almost exactly\r
+what you want with the program, including distributing it among your\r
+friends, making it available for download from your web site, selling\r
+it (either by itself or as part of some bigger software package), or\r
+using it as the starting point for a software project of your own.\r
+\r
+The only real limitation is that whenever you distribute Glaurung in\r
+some way, you must always include the full source code, or a pointer\r
+to where the source code can be found.  If you make any changes to the\r
+source code, these changes must also be made available under the GPL.\r
+\r
+For full details, read the copy of the GPL found in the file named\r
+Copying.txt.\r
+\r
+\r
+7. Feedback\r
+-----------\r
+\r
+The author's e-mail address is tord@glaurungchess.com\r
+\r
diff --git a/polyglot.ini b/polyglot.ini
new file mode 100644 (file)
index 0000000..7d5c8d9
--- /dev/null
@@ -0,0 +1,70 @@
+\r
+[PolyGlot]\r
+\r
+EngineDir = .\r
+EngineCommand = ./glaurung\r
+\r
+Book = false\r
+BookFile = book.bin\r
+\r
+Log = true\r
+LogFile = glaurung.log\r
+\r
+Resign = true\r
+ResignScore = 600\r
+\r
+[Engine]\r
+\r
+Hash = 128\r
+Threads = 1\r
+OwnBook = false\r
+Book File = book.bin\r
+Use Search Log = false\r
+Mobility (Middle Game) = 100\r
+Mobility (Endgame) = 100\r
+Pawn Structure (Middle Game) = 100\r
+Pawn Structure (Endgame) = 100\r
+Passed Pawns (Middle Game) = 100\r
+Passed Pawns (Endgame) = 100\r
+Aggressiveness = 100\r
+Cowardice = 100\r
+King Safety Curve = Quadratic\r
+Quadratic = Linear\r
+King Safety Coefficient = 40\r
+King Safety X Intercept = 0\r
+King Safety Max Slope = 30\r
+King Safety Max Value = 500\r
+Queen Contact Check Bonus = 4\r
+Rook Contact Check Bonus = 2\r
+Queen Check Bonus = 2\r
+Rook Check Bonus = 1\r
+Bishop Check Bonus = 1\r
+Knight Check Bonus = 1\r
+Discovered Check Bonus = 3\r
+Mate Threat Bonus = 3\r
+Check Extension (PV nodes) = 2\r
+Check Extension (non-PV nodes) = 1\r
+Single Reply Extension (PV nodes) = 2\r
+Single Reply Extension (non-PV nodes) = 2\r
+Mate Threat Extension (PV nodes) = 0\r
+Mate Threat Extension (non-PV nodes) = 0\r
+Pawn Push to 7th Extension (PV nodes) = 1\r
+Pawn Push to 7th Extension (non-PV nodes) = 1\r
+Passed Pawn Extension (PV nodes) = 1\r
+Passed Pawn Extension (non-PV nodes) = 0\r
+Pawn Endgame Extension (PV nodes) = 2\r
+Pawn Endgame Extension (non-PV nodes) = 2\r
+Full Depth Moves (PV nodes) = 14\r
+Full Depth Moves (non-PV nodes) = 3\r
+Threat Depth = 5\r
+Selective Plies = 7\r
+Futility Pruning (Main Search) = true\r
+Futility Pruning (Quiescence Search) = true\r
+Futility Margin 0 = 50\r
+Futility Margin 1 = 100\r
+Futility Margin 2 = 300\r
+Maximum Razoring Depth = 3\r
+Razoring Margin = 300\r
+Randomness = 0\r
+Minimum Split Depth = 4\r
+Maximum Number of Threads per Split Point = 5\r
diff --git a/src/COPYING b/src/COPYING
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/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..2e37ccc
--- /dev/null
@@ -0,0 +1,145 @@
+# Glaurung, a UCI chess playing engine.
+# Copyright (C) 2004-2007 Tord Romstad
+
+# This file is part of Glaurung.
+#
+# Glaurung 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.
+#
+# Glaurung 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/>.
+
+
+###
+### Files
+###
+
+EXE = glaurung
+
+OBJS = bitboard.o color.o pawns.o material.o endgame.o evaluate.o main.o \
+       misc.o move.o movegen.o history.o movepick.o search.o piece.o \
+       position.o square.o direction.o tt.o value.o uci.o ucioption.o \
+       mersenne.o book.o bitbase.o san.o benchmark.o
+
+
+###
+### Rules
+###
+
+all: $(EXE) .depend
+
+clean: 
+       $(RM) *.o .depend glaurung
+
+
+###
+### Compiler:
+###
+
+CXX = g++
+# CXX = g++-4.2
+# CXX = icpc
+
+
+###
+### Dependencies
+###
+
+$(EXE): $(OBJS)
+       $(CXX) $(LDFLAGS) -o $@ $(OBJS)
+
+.depend:
+       $(CXX) -MM $(OBJS:.o=.cpp) > $@
+
+include .depend
+
+
+###
+### Compiler and linker switches
+###
+
+# Enable/disable debugging:
+
+CXXFLAGS += -DNDEBUG
+
+
+# Compile with full warnings, and symbol names
+
+CXXFLAGS += -Wall -g
+
+
+# General optimization flags.  Note that -O2 might be faster than -O3 on some
+# systems; this requires testing.
+
+CXXFLAGS += -O3 -fno-exceptions -fomit-frame-pointer -fno-rtti -fstrict-aliasing
+
+
+# Compiler optimization flags for the Intel C++ compiler in Mac OS X:
+
+# CXXFLAGS += -mdynamic-no-pic -no-prec-div -ipo -static -xP
+
+
+# Profiler guided optimization with the Intel C++ compiler.  To use it, first
+# create the directory ./profdata if it does not already exist, and delete its
+# contents if it does exist.  Then compile with -prof_gen, and run the 
+# resulting binary for a while (for instance, do ./glaurung bench 128 1, and
+# wait 15 minutes for the benchmark to complete).  Then do a 'make clean', and 
+# recompile with -prof_use.
+
+# CXXFLAGS += -prof_gen -prof_dir ./profdata
+# CXXFLAGS += -prof_use -prof_dir ./profdata
+
+
+# Profiler guided optimization with GCC.  I've never been able to make this 
+# work.
+
+# CXXFLAGS += -fprofile-generate
+# LDFLAGS += -fprofile-generate
+# CXXFLAGS += -fprofile-use
+# CXXFLAGS += -fprofile-use
+
+
+# General linker flags
+
+LDFLAGS += -lm -lpthread
+
+
+# Compiler switches for generating binaries for various CPUs in Mac OS X.
+# Note that 'arch ppc' and 'arch ppc64' only works with g++, and not with
+# the intel compiler.
+
+# CXXFLAGS += -arch ppc
+# CXXFLAGS += -arch ppc64
+# CXXFLAGS += -arch i386
+# CXXFLAGS += -arch x86_64
+# LDFLAGS += -arch ppc
+# LDFLAGS += -arch ppc64
+# LDFLAGS += -arch i386
+# LDFLAGS += -arch x86_64
+
+
+# Backwards compatibility with Mac OS X 10.4 when compiling under 10.5 with 
+# GCC 4.0.  I haven't found a way to make it work with GCC 4.2.
+
+# CXXFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk
+# CXXFLAGS += -mmacosx-version-min=10.4
+# LDFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk
+# LDFLAGS += -Wl,-syslibroot /Developer/SDKs/MacOSX10.4u.sdk
+# LDFLAGS += -mmacosx-version-min=10.4
+
+
+# Backwards compatibility with Mac OS X 10.4 when compiling with ICC.  Doesn't
+# work yet. :-(
+
+# CXXFLAGS += -DMAC_OS_X_VERSION_MIN_REQUIRED=1040
+# CXXFLAGS += -DMAC_OS_X_VERSION_MAX_ALLOWED=1040
+# CXXFLAGS += -D__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1040
+# CXXFLAGS += -F/Developer/SDKs/MacOSX10.4u.sdk/
+# LDFLAGS += -Wl,-syslibroot -Wl,/Developer/SDKs/MacOSX10.4u.sdk
diff --git a/src/benchmark.cpp b/src/benchmark.cpp
new file mode 100644 (file)
index 0000000..4bd1ac8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include "benchmark.h"
+#include "search.h"
+#include "thread.h"
+#include "ucioption.h"
+
+
+////
+//// Variables
+////
+
+const std::string BenchmarkPositions[15] = {
+  "r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
+  "4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20",
+  "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"
+};
+  
+
+////
+//// Functions
+////
+
+/// benchmark() runs a simple benchmark by letting Glaurung analyze 15
+/// positions for 60 seconds each.  There are two parameters; the
+/// transposition table size and the number of search threads that should
+/// be used.  The analysis is written to a file named bench.txt.
+
+void benchmark(const std::string &ttSize, const std::string &threads) {
+  Position pos;
+  Move moves[1] = {MOVE_NONE};
+  int i;
+
+  i = atoi(ttSize.c_str());
+  if(i < 4 || i > 1024) {
+    std::cerr << "The hash table size must be between 4 and 1024" << std::endl;
+    exit(EXIT_FAILURE);
+  }
+
+  i = atoi(threads.c_str());
+  if(i < 1 || i > THREAD_MAX) {
+    std::cerr << "The number of threads must be between 1 and " << THREAD_MAX
+              << std::endl;
+    exit(EXIT_FAILURE);
+  }
+  
+  set_option_value("Hash", ttSize);
+  set_option_value("Threads", threads);
+  set_option_value("OwnBook", "false");
+  set_option_value("Use Search Log", "true");
+  set_option_value("Search Log Filename", "bench.txt");
+
+  for(i = 0; i < 15; i++) {
+    pos.from_fen(BenchmarkPositions[i]);
+    think(pos, true, false, 0, 0, 0, 0, 0, 60000, moves);
+  }
+    
+}
diff --git a/src/benchmark.h b/src/benchmark.h
new file mode 100644 (file)
index 0000000..9ca68f8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(BENCHMARK_H_INCLUDED)
+#define BENCHMARK_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include <string>
+
+
+////
+//// Prototypes
+////
+
+extern void benchmark(const std::string &ttSize, const std::string &threads);
+
+
+#endif // !defined(BENCHMARK_H_INCLUDED)
diff --git a/src/bitbase.cpp b/src/bitbase.cpp
new file mode 100644 (file)
index 0000000..80db0a4
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+
+#include "bitbase.h"
+#include "bitboard.h"
+#include "move.h"
+#include "square.h"
+
+
+////
+//// Local definitions
+////
+
+namespace {
+
+  enum Result {
+    RESULT_UNKNOWN,
+    RESULT_INVALID,
+    RESULT_WIN,
+    RESULT_LOSS,
+    RESULT_DRAW
+  };
+
+  struct KPKPosition {
+    void from_index(int index);
+    int to_index() const;
+    bool is_legal() const;
+    bool is_immediate_draw() const;
+    bool is_immediate_win() const;
+    Bitboard wk_attacks() const;
+    Bitboard bk_attacks() const;
+    Bitboard pawn_attacks() const;
+    
+    Square whiteKingSquare, blackKingSquare, pawnSquare;
+    Color sideToMove;
+  };
+    
+
+  Result *Bitbase;
+  const int IndexMax = 2*24*64*64;
+  int UnknownCount = 0;
+
+  void initialize();
+  bool next_iteration();
+  Result classify_wtm(const KPKPosition &p);
+  Result classify_btm(const KPKPosition &p);
+  int compute_index(Square wksq, Square bksq, Square psq, Color stm);
+  int compress_result(Result r);
+  
+}
+
+
+////
+//// Functions
+////
+
+void generate_kpk_bitbase(uint8_t bitbase[]) {
+  // Allocate array and initialize:
+  Bitbase = new Result[IndexMax];
+  initialize();
+
+  // Iterate until all positions are classified:
+  while(next_iteration());
+
+  // Compress bitbase into the supplied parameter:
+  int i, j, b;
+  for(i = 0; i < 24576; i++) {
+    for(b = 0, j = 0; j < 8; b |= (compress_result(Bitbase[8*i+j]) << j), j++);
+    bitbase[i] = b;
+  }
+
+  // Release allocated memory:
+  delete [] Bitbase;
+}
+
+
+namespace {
+
+  void KPKPosition::from_index(int index) {
+    int s;
+    sideToMove = Color(index % 2);
+    blackKingSquare = Square((index / 2) % 64);
+    whiteKingSquare = Square((index / 128) % 64);
+    s = (index / 8192) % 24;
+    pawnSquare = make_square(File(s % 4), Rank(s / 4 + 1));
+  }
+
+
+  int KPKPosition::to_index() const {
+    return compute_index(whiteKingSquare, blackKingSquare, pawnSquare,
+                         sideToMove);
+  }
+    
+
+  bool KPKPosition::is_legal() const {
+    if(whiteKingSquare == pawnSquare || whiteKingSquare == blackKingSquare ||
+       pawnSquare == blackKingSquare)
+      return false;
+    if(sideToMove == WHITE) {
+      if(bit_is_set(this->wk_attacks(), blackKingSquare))
+        return false;
+      if(bit_is_set(this->pawn_attacks(), blackKingSquare))
+        return false;
+    }
+    else {
+      if(bit_is_set(this->bk_attacks(), whiteKingSquare))
+        return false;
+    }
+    return true;
+  }
+
+
+  bool KPKPosition::is_immediate_draw() const {
+    if(sideToMove == BLACK) {
+      Bitboard wka = this->wk_attacks();
+      Bitboard bka = this->bk_attacks();
+    
+      // Case 1: Stalemate
+      if((bka & ~(wka | this->pawn_attacks())) == EmptyBoardBB)
+        return true;
+
+      // Case 2: King can capture pawn
+      if(bit_is_set(bka, pawnSquare) && !bit_is_set(wka, pawnSquare))
+        return true;
+    }
+    else {
+      // Case 1: Stalemate
+      if(whiteKingSquare == SQ_A8 && pawnSquare == SQ_A7 &&
+         (blackKingSquare == SQ_C7 || blackKingSquare == SQ_C8))
+        return true;
+    }
+
+    return false;
+  }
+
+
+  bool KPKPosition::is_immediate_win() const {
+    // The position is an immediate win if it is white to move and the white
+    // pawn can be promoted without getting captured:
+    return
+      sideToMove == WHITE &&
+      square_rank(pawnSquare) == RANK_7 &&
+      (square_distance(blackKingSquare, pawnSquare+DELTA_N) > 1 ||
+       bit_is_set(this->wk_attacks(), pawnSquare+DELTA_N));
+  }
+    
+
+  Bitboard KPKPosition::wk_attacks() const {
+    return StepAttackBB[WK][whiteKingSquare];
+  }
+
+
+  Bitboard KPKPosition::bk_attacks() const {
+    return StepAttackBB[BK][blackKingSquare];
+  }
+
+
+  Bitboard KPKPosition::pawn_attacks() const {
+    return StepAttackBB[WP][pawnSquare];
+  }
+
+
+  void initialize() {
+    KPKPosition p;
+    for(int i = 0; i < IndexMax; i++) {
+      p.from_index(i);
+      if(!p.is_legal())
+        Bitbase[i] = RESULT_INVALID;
+      else if(p.is_immediate_draw())
+        Bitbase[i] = RESULT_DRAW;
+      else if(p.is_immediate_win())
+        Bitbase[i] = RESULT_WIN;
+      else {
+        Bitbase[i] = RESULT_UNKNOWN;
+        UnknownCount++;
+      }
+    }
+  }
+
+
+  bool next_iteration() {
+    KPKPosition p;
+    int previousUnknownCount = UnknownCount;
+    
+    for(int i = 0; i < IndexMax; i++)
+      if(Bitbase[i] == RESULT_UNKNOWN) {
+        p.from_index(i);
+
+        Bitbase[i] = (p.sideToMove == WHITE)? classify_wtm(p) : classify_btm(p);
+
+        if(Bitbase[i] == RESULT_WIN || Bitbase[i] == RESULT_LOSS ||
+           Bitbase[i] == RESULT_DRAW)
+          UnknownCount--;
+      }
+
+    return UnknownCount != previousUnknownCount;
+  }
+
+
+  Result classify_wtm(const KPKPosition &p) {
+
+    // If one move leads to a position classified as RESULT_LOSS, the result
+    // of the current position is RESULT_WIN.  If all moves lead to positions
+    // classified as RESULT_DRAW, the current position is classified as
+    // RESULT_DRAW.  Otherwise, the current position is classified as
+    // RESULT_UNKNOWN.
+
+    bool unknownFound = false;
+    Bitboard b;
+    Square s;
+    
+    // King moves
+    b = p.wk_attacks();
+    while(b) {
+      s = pop_1st_bit(&b);
+      switch(Bitbase[compute_index(s, p.blackKingSquare, p.pawnSquare,
+                                   BLACK)]) {
+      case RESULT_LOSS:
+        return RESULT_WIN;
+
+      case RESULT_UNKNOWN:
+        unknownFound = true;
+        break;
+
+      case RESULT_DRAW: case RESULT_INVALID:
+        break;
+
+      default:
+        assert(false);
+      }
+    }
+
+    // Pawn moves
+    if(square_rank(p.pawnSquare) < RANK_7) {
+      s = p.pawnSquare + DELTA_N;
+      switch(Bitbase[compute_index(p.whiteKingSquare, p.blackKingSquare, s,
+                                   BLACK)]) {
+      case RESULT_LOSS:
+        return RESULT_WIN;
+        
+      case RESULT_UNKNOWN:
+        unknownFound = true;
+        break;
+          
+      case RESULT_DRAW: case RESULT_INVALID:
+        break;
+        
+      default:
+        assert(false);
+      }
+
+      if(square_rank(s) == RANK_3 &&
+         s != p.whiteKingSquare && s != p.blackKingSquare) {
+        s += DELTA_N;
+        switch(Bitbase[compute_index(p.whiteKingSquare, p.blackKingSquare, s,
+                                     BLACK)]) {
+        case RESULT_LOSS:
+          return RESULT_WIN;
+          
+        case RESULT_UNKNOWN:
+          unknownFound = true;
+          break;
+          
+        case RESULT_DRAW: case RESULT_INVALID:
+          break;
+          
+        default:
+          assert(false);
+        }
+      }
+    }
+    
+    return unknownFound? RESULT_UNKNOWN : RESULT_DRAW;
+  }
+
+
+  Result classify_btm(const KPKPosition &p) {
+
+    // If one move leads to a position classified as RESULT_DRAW, the result
+    // of the current position is RESULT_DRAW.  If all moves lead to positions
+    // classified as RESULT_WIN, the current position is classified as
+    // RESULT_LOSS.  Otherwise, the current position is classified as
+    // RESULT_UNKNOWN.
+
+    bool unknownFound = false;
+    Bitboard b;
+    Square s;
+
+    // King moves
+    b = p.bk_attacks();
+    while(b) {
+      s = pop_1st_bit(&b);
+      switch(Bitbase[compute_index(p.whiteKingSquare, s, p.pawnSquare,
+                                   WHITE)]) {
+      case RESULT_DRAW:
+        return RESULT_DRAW;
+
+      case RESULT_UNKNOWN:
+        unknownFound = true;
+        break;
+
+      case RESULT_WIN: case RESULT_INVALID:
+        break;
+
+      default:
+        assert(false);
+      }
+    }
+
+    return unknownFound? RESULT_UNKNOWN : RESULT_LOSS;
+  }
+
+
+  int compute_index(Square wksq, Square bksq, Square psq, Color stm) {
+    int p = int(square_file(psq)) + (int(square_rank(psq)) - 1) * 4;
+    int result = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*p;
+    assert(result >= 0 && result < IndexMax);
+    return result;
+  }
+
+
+  int compress_result(Result r) {
+    return (r == RESULT_WIN || r == RESULT_LOSS)? 1 : 0;
+  }
+      
+}  
diff --git a/src/bitbase.h b/src/bitbase.h
new file mode 100644 (file)
index 0000000..2de5413
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(BITBASE_H_INCLUDED)
+#define BITBASE_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "types.h"
+
+
+////
+//// Prototypes
+////
+
+extern void generate_kpk_bitbase(uint8_t bitbase[]);
+
+
+#endif // !defined(BITBASE_H_INCLUDED)
diff --git a/src/bitboard.cpp b/src/bitboard.cpp
new file mode 100644 (file)
index 0000000..0bbd155
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <iostream>
+
+#include "bitboard.h"
+#include "direction.h"
+
+
+////
+//// Constants and variables
+////
+
+const Bitboard SquaresByColorBB[2] = {BlackSquaresBB, WhiteSquaresBB};
+
+const Bitboard FileBB[8] = {
+  FileABB, FileBBB, FileCBB, FileDBB, FileEBB, FileFBB, FileGBB, FileHBB
+};
+
+const Bitboard NeighboringFilesBB[8] = {
+  FileBBB, FileABB|FileCBB, FileBBB|FileDBB, FileCBB|FileEBB, 
+  FileDBB|FileFBB, FileEBB|FileGBB, FileFBB|FileHBB, FileGBB
+};
+
+const Bitboard ThisAndNeighboringFilesBB[8] = {
+  FileABB|FileBBB, FileABB|FileBBB|FileCBB,
+  FileBBB|FileCBB|FileDBB, FileCBB|FileDBB|FileEBB,
+  FileDBB|FileEBB|FileFBB, FileEBB|FileFBB|FileGBB,
+  FileFBB|FileGBB|FileHBB, FileGBB|FileHBB
+};  
+
+const Bitboard RankBB[8] = {
+  Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
+};
+
+const Bitboard RelativeRankBB[2][8] = {
+  {
+    Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
+  },
+  {
+    Rank8BB, Rank7BB, Rank6BB, Rank5BB, Rank4BB, Rank3BB, Rank2BB, Rank1BB
+  }
+};
+
+const Bitboard InFrontBB[2][8] = {
+  {
+    Rank2BB | Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
+    Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
+    Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
+    Rank5BB | Rank6BB | Rank7BB | Rank8BB,
+    Rank6BB | Rank7BB | Rank8BB,
+    Rank7BB | Rank8BB,
+    Rank8BB,
+    EmptyBoardBB
+  },
+  {
+    EmptyBoardBB,
+    Rank1BB,
+    Rank2BB | Rank1BB,
+    Rank3BB | Rank2BB | Rank1BB,
+    Rank4BB | Rank3BB | Rank2BB | Rank1BB,
+    Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
+    Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
+    Rank7BB | Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB
+  }
+};
+
+#if defined(USE_COMPACT_ROOK_ATTACKS)
+
+Bitboard RankAttacks[8][64], FileAttacks[8][64];
+
+#elif defined(USE_32BIT_ATTACKS)
+
+const uint64_t RMult[64] = {
+  0xd7445cdec88002c0ULL, 0xd0a505c1f2001722ULL, 0xe065d1c896002182ULL,
+  0x9a8c41e75a000892ULL, 0x8900b10c89002aa8ULL, 0x9b28d1c1d60005a2ULL,
+  0x15d6c88de002d9aULL, 0xb1dbfc802e8016a9ULL, 0x149a1042d9d60029ULL,
+  0xb9c08050599e002fULL, 0x132208c3af300403ULL, 0xc1000ce2e9c50070ULL,
+  0x9d9aa13c99020012ULL, 0xb6b078daf71e0046ULL, 0x9d880182fb6e002eULL,
+  0x52889f467e850037ULL, 0xda6dc008d19a8480ULL, 0x468286034f902420ULL,
+  0x7140ac09dc54c020ULL, 0xd76ffffa39548808ULL, 0xea901c4141500808ULL,
+  0xc91004093f953a02ULL, 0x2882afa8f6bb402ULL, 0xaebe335692442c01ULL,
+  0xe904a22079fb91eULL, 0x13a514851055f606ULL, 0x76c782018c8fe632ULL,
+  0x1dc012a9d116da06ULL, 0x3c9e0037264fffa6ULL, 0x2036002853c6e4a2ULL,
+  0xe3fe08500afb47d4ULL, 0xf38af25c86b025c2ULL, 0xc0800e2182cf9a40ULL,
+  0x72002480d1f60673ULL, 0x2500200bae6e9b53ULL, 0xc60018c1eefca252ULL,
+  0x600590473e3608aULL, 0x46002c4ab3fe51b2ULL, 0xa200011486bcc8d2ULL,
+  0xb680078095784c63ULL, 0x2742002639bf11aeULL, 0xc7d60021a5bdb142ULL,
+  0xc8c04016bb83d820ULL, 0xbd520028123b4842ULL, 0x9d1600344ac2a832ULL,
+  0x6a808005631c8a05ULL, 0x604600a148d5389aULL, 0xe2e40103d40dea65ULL,
+  0x945b5a0087c62a81ULL, 0x12dc200cd82d28eULL, 0x2431c600b5f9ef76ULL,
+  0xfb142a006a9b314aULL, 0x6870e00a1c97d62ULL, 0x2a9db2004a2689a2ULL,
+  0xd3594600caf5d1a2ULL, 0xee0e4900439344a7ULL, 0x89c4d266ca25007aULL,
+  0x3e0013a2743f97e3ULL, 0x180e31a0431378aULL, 0x3a9e465a4d42a512ULL,
+  0x98d0a11a0c0d9cc2ULL, 0x8e711c1aba19b01eULL, 0x8dcdc836dd201142ULL,
+  0x5ac08a4735370479ULL,
+};
+
+const int RShift[64] = {
+  20, 21, 21, 21, 21, 21, 21, 20, 21, 22, 22, 22, 22, 22, 22, 21,
+  21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
+  21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
+  21, 22, 22, 22, 22, 22, 22, 21, 20, 21, 21, 21, 21, 21, 21, 20
+};
+
+#else // if defined(USE_32BIT_ATTACKS)
+
+const uint64_t RMult[64] = {
+  0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL, 
+  0x380180080141000ULL, 0x1a00060008211044ULL, 0x410001000a0c0008ULL, 
+  0x9500060004008100ULL, 0x100024284a20700ULL, 0x802140008000ULL, 
+  0x80c01002a00840ULL, 0x402004282011020ULL, 0x9862000820420050ULL, 
+  0x1001448011100ULL, 0x6432800200800400ULL, 0x40100010002000cULL, 
+  0x2800d0010c080ULL, 0x90c0008000803042ULL, 0x4010004000200041ULL, 
+  0x3010010200040ULL, 0xa40828028001000ULL, 0x123010008000430ULL, 
+  0x24008004020080ULL, 0x60040001104802ULL, 0x582200028400d1ULL, 
+  0x4000802080044000ULL, 0x408208200420308ULL, 0x610038080102000ULL, 
+  0x3601000900100020ULL, 0x80080040180ULL, 0xc2020080040080ULL, 
+  0x80084400100102ULL, 0x4022408200014401ULL, 0x40052040800082ULL, 
+  0xb08200280804000ULL, 0x8a80a008801000ULL, 0x4000480080801000ULL, 
+  0x911808800801401ULL, 0x822a003002001894ULL, 0x401068091400108aULL, 
+  0x4a10a00004cULL, 0x2000800640008024ULL, 0x1486408102020020ULL, 
+  0x100a000d50041ULL, 0x810050020b0020ULL, 0x204000800808004ULL, 
+  0x20048100a000cULL, 0x112000831020004ULL, 0x9000040810002ULL, 
+  0x440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL, 
+  0x4b824a2010010100ULL, 0x4080801810c0080ULL, 0x400802a0080ULL, 
+  0x8224080110026400ULL, 0x40002c4104088200ULL, 0x1002100104a0282ULL, 
+  0x1208400811048021ULL, 0x3201014a40d02001ULL, 0x5100019200501ULL, 
+  0x101000208001005ULL, 0x2008450080702ULL, 0x1002080301d00cULL, 
+  0x410201ce5c030092ULL
+};
+
+const int RShift[64] = {
+  52, 53, 53, 53, 53, 53, 53, 52, 53, 54, 54, 54, 54, 54, 54, 53,
+  53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
+  53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
+  53, 54, 54, 54, 54, 54, 54, 53, 52, 53, 53, 53, 53, 53, 53, 52
+};
+
+#endif // defined(USE_32BIT_ATTACKS)
+
+#if !defined(USE_COMPACT_ROOK_ATTACKS)
+Bitboard RMask[64];
+int RAttackIndex[64];
+Bitboard RAttacks[0x19000];
+#endif
+
+#if defined(USE_32BIT_ATTACKS)
+
+const uint64_t BMult[64] = {
+  0x54142844c6a22981ULL, 0x710358a6ea25c19eULL, 0x704f746d63a4a8dcULL,
+  0xbfed1a0b80f838c5ULL, 0x90561d5631e62110ULL, 0x2804260376e60944ULL,
+  0x84a656409aa76871ULL, 0xf0267f64c28b6197ULL, 0x70764ebb762f0585ULL,
+  0x92aa09e0cfe161deULL, 0x41ee1f6bb266f60eULL, 0xddcbf04f6039c444ULL,
+  0x5a3fab7bac0d988aULL, 0xd3727877fa4eaa03ULL, 0xd988402d868ddaaeULL,
+  0x812b291afa075c7cULL, 0x94faf987b685a932ULL, 0x3ed867d8470d08dbULL,
+  0x92517660b8901de8ULL, 0x2d97e43e058814b4ULL, 0x880a10c220b25582ULL,
+  0xc7c6520d1f1a0477ULL, 0xdbfc7fbcd7656aa6ULL, 0x78b1b9bfb1a2b84fULL,
+  0x2f20037f112a0bc1ULL, 0x657171ea2269a916ULL, 0xc08302b07142210eULL,
+  0x880a4403064080bULL, 0x3602420842208c00ULL, 0x852800dc7e0b6602ULL,
+  0x595a3fbbaa0f03b2ULL, 0x9f01411558159d5eULL, 0x2b4a4a5f88b394f2ULL,
+  0x4afcbffc292dd03aULL, 0x4a4094a3b3f10522ULL, 0xb06f00b491f30048ULL,
+  0xd5b3820280d77004ULL, 0x8b2e01e7c8e57a75ULL, 0x2d342794e886c2e6ULL,
+  0xc302c410cde21461ULL, 0x111f426f1379c274ULL, 0xe0569220abb31588ULL,
+  0x5026d3064d453324ULL, 0xe2076040c343cd8aULL, 0x93efd1e1738021eeULL,
+  0xb680804bed143132ULL, 0x44e361b21986944cULL, 0x44c60170ef5c598cULL,
+  0xf4da475c195c9c94ULL, 0xa3afbb5f72060b1dULL, 0xbc75f410e41c4ffcULL,
+  0xb51c099390520922ULL, 0x902c011f8f8ec368ULL, 0x950b56b3d6f5490aULL,
+  0x3909e0635bf202d0ULL, 0x5744f90206ec10ccULL, 0xdc59fd76317abbc1ULL,
+  0x881c7c67fcbfc4f6ULL, 0x47ca41e7e440d423ULL, 0xeb0c88112048d004ULL,
+  0x51c60e04359aef1aULL, 0x1aa1fe0e957a5554ULL, 0xdd9448db4f5e3104ULL,
+  0xdc01f6dca4bebbdcULL,
+}; 
+
+const int BShift[64] = {
+  26, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+  27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 25, 23, 23, 25, 27, 27,
+  27, 27, 25, 23, 23, 25, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27,
+  27, 27, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 26
+};
+
+#else // if defined(USE_32BIT_ATTACKS)
+
+const uint64_t BMult[64] = {
+  0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL, 
+  0x48c4440084048090ULL, 0x2801104026490000ULL, 0x4100880442040800ULL, 
+  0x181011002e06040ULL, 0x9101004104200e00ULL, 0x1240848848310401ULL, 
+  0x2000142828050024ULL, 0x1004024d5000ULL, 0x102044400800200ULL, 
+  0x8108108820112000ULL, 0xa880818210c00046ULL, 0x4008008801082000ULL, 
+  0x60882404049400ULL, 0x104402004240810ULL, 0xa002084250200ULL, 
+  0x100b0880801100ULL, 0x4080201220101ULL, 0x44008080a00000ULL, 
+  0x202200842000ULL, 0x5006004882d00808ULL, 0x200045080802ULL, 
+  0x86100020200601ULL, 0xa802080a20112c02ULL, 0x80411218080900ULL, 
+  0x200a0880080a0ULL, 0x9a01010000104000ULL, 0x28008003100080ULL, 
+  0x211021004480417ULL, 0x401004188220806ULL, 0x825051400c2006ULL, 
+  0x140c0210943000ULL, 0x242800300080ULL, 0xc2208120080200ULL, 
+  0x2430008200002200ULL, 0x1010100112008040ULL, 0x8141050100020842ULL, 
+  0x822081014405ULL, 0x800c049e40400804ULL, 0x4a0404028a000820ULL, 
+  0x22060201041200ULL, 0x360904200840801ULL, 0x881a08208800400ULL, 
+  0x60202c00400420ULL, 0x1204440086061400ULL, 0x8184042804040ULL, 
+  0x64040315300400ULL, 0xc01008801090a00ULL, 0x808010401140c00ULL, 
+  0x4004830c2020040ULL, 0x80005002020054ULL, 0x40000c14481a0490ULL, 
+  0x10500101042048ULL, 0x1010100200424000ULL, 0x640901901040ULL, 
+  0xa0201014840ULL, 0x840082aa011002ULL, 0x10010840084240aULL, 
+  0x420400810420608ULL, 0x8d40230408102100ULL, 0x4a00200612222409ULL, 
+  0xa08520292120600ULL
+};
+
+const int BShift[64] = {
+  58, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 59, 59,
+  59, 59, 57, 57, 57, 57, 59, 59, 59, 59, 57, 55, 55, 57, 59, 59,
+  59, 59, 57, 55, 55, 57, 59, 59, 59, 59, 57, 57, 57, 57, 59, 59,
+  59, 59, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 58
+};
+
+#endif // defined(USE_32BIT_ATTACKS)
+
+Bitboard BMask[64];
+int BAttackIndex[64];
+Bitboard BAttacks[0x1480];
+
+Bitboard SetMaskBB[64];
+Bitboard ClearMaskBB[64];
+
+Bitboard StepAttackBB[16][64];
+Bitboard RayBB[64][8];
+Bitboard BetweenBB[64][64];
+
+Bitboard PassedPawnMask[2][64];
+Bitboard OutpostMask[2][64];
+
+Bitboard BishopPseudoAttacks[64];
+Bitboard RookPseudoAttacks[64];
+Bitboard QueenPseudoAttacks[64];
+
+
+////
+//// Local definitions
+////
+
+namespace {
+  void init_masks();
+  void init_ray_bitboards();
+  void init_attacks();
+  void init_between_bitboards();
+  Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
+                           int fmin, int fmax, int rmin, int rmax);
+  Bitboard index_to_bitboard(int index, Bitboard mask);
+  void init_sliding_attacks(Bitboard attacks[],
+                            int attackIndex[], Bitboard mask[],
+                            const int shift[2], const Bitboard mult[],
+                            int deltas[][2]);
+  void init_pseudo_attacks();
+#if defined(USE_COMPACT_ROOK_ATTACKS)
+  void init_file_and_rank_attacks();
+#endif
+};
+
+
+////
+//// Functions
+////
+
+/// print_bitboard() prints a bitboard in an easily readable format to the
+/// standard output.  This is sometimes useful for debugging.
+
+void print_bitboard(Bitboard b) {
+  for(Rank r = RANK_8; r >= RANK_1; r--) {
+    std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
+    for(File f = FILE_A; f <= FILE_H; f++)
+      std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
+    std::cout << "|" << std::endl;
+  }
+  std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
+}
+
+
+/// init_bitboards() initializes various bitboard arrays.  It is called during
+/// program initialization.
+
+void init_bitboards() {
+  int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
+  int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
+  init_masks();
+  init_ray_bitboards();
+  init_attacks();
+  init_between_bitboards();
+#if defined(USE_COMPACT_ROOK_ATTACKS)
+  init_file_and_rank_attacks();
+#else
+  init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift,
+                       RMult, rookDeltas);
+#endif
+  init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift,
+                       BMult, bishopDeltas);
+  init_pseudo_attacks();
+}
+
+
+#if defined(USE_FOLDED_BITSCAN)
+
+static const int BitTable[64] = {
+  63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2, 
+  51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52, 
+  26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28, 
+  58, 20, 37, 17, 36, 8
+};
+
+
+/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
+
+Square first_1(Bitboard b) {
+  b ^= (b - 1);
+  uint32_t fold = int(b) ^ int(b >> 32);
+  return Square(BitTable[(fold * 0x783a9b23) >> 26]);
+}
+
+
+/// pop_1st_bit() finds and clears the least significant nonzero bit in a
+/// nonzero bitboard.
+
+Square pop_1st_bit(Bitboard *b) {
+  Bitboard bb = *b ^ (*b - 1);
+  uint32_t fold = int(bb) ^ int(bb >> 32);
+  *b &= (*b - 1);
+  return Square(BitTable[(fold * 0x783a9b23) >> 26]);
+}
+
+#else
+
+static const int BitTable[64] = {
+  0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15,
+  46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39,
+  16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43,
+  51, 60, 42, 59, 58
+};
+
+
+/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
+
+Square first_1(Bitboard b) {
+  return Square(BitTable[((b & -b) * 0x218a392cd3d5dbfULL) >> 58]);
+}
+
+
+/// pop_1st_bit() finds and clears the least significant nonzero bit in a
+/// nonzero bitboard.
+
+Square pop_1st_bit(Bitboard *b) {
+  Bitboard bb = *b;
+  *b &= (*b - 1);
+  return Square(BitTable[((bb & -bb) * 0x218a392cd3d5dbfULL) >> 58]); 
+}
+
+#endif // defined(USE_FOLDED_BITSCAN)
+
+
+namespace {
+
+  // All functions below are used to precompute various bitboards during
+  // program initialization.  Some of the functions may be difficult to
+  // understand, but they all seem to work correctly, and it should never
+  // be necessary to touch any of them.
+
+  void init_masks() {
+    for(Square s = SQ_A1; s <= SQ_H8; s++) {
+      SetMaskBB[s] = (1ULL << s);
+      ClearMaskBB[s] = ~SetMaskBB[s];
+    }
+    for(Color c = WHITE; c <= BLACK; c++)
+      for(Square s = SQ_A1; s <= SQ_H8; s++) {
+        PassedPawnMask[c][s] =
+          in_front_bb(c, s) & this_and_neighboring_files_bb(s);
+        OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
+      }
+  }
+
+
+  void init_ray_bitboards() {
+    int d[8] = {1, -1, 16, -16, 17, -17, 15, -15};
+    for(int i = 0; i < 128; i = i + 9 & ~8) {
+      for(int j = 0; j < 8; j++) {
+        RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB;
+        for(int k = i + d[j]; (k & 0x88) == 0; k += d[j])
+          set_bit(&(RayBB[(i&7)|((i>>4)<<3)][j]), Square((k&7)|((k>>4)<<3)));
+      }
+    }
+  }
+
+
+  void init_attacks() {
+    int i, j, k, l;
+    int step[16][8] =  {
+      {0},
+      {7,9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0},
+      {9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}, {0}, {0},
+      {-7,-9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0},
+      {9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}
+    };
+    
+    for(i = 0; i < 64; i++) {
+      for(j = 0; j <= int(BK); j++) {
+        StepAttackBB[j][i] = EmptyBoardBB;
+        for(k = 0; k < 8 && step[j][k] != 0; k++) {
+          l = i + step[j][k];
+          if(l >= 0 && l < 64 && abs((i&7) - (l&7)) < 3)
+            StepAttackBB[j][i] |= (1ULL << l);
+        }
+      }
+    }
+  }
+
+
+  Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
+                           int fmin=0, int fmax=7, int rmin=0, int rmax=7) {
+    Bitboard result = 0ULL;
+    int rk = sq / 8, fl = sq % 8, r, f, i;
+    for(i = 0; i < dirs; i++) {
+      int dx = deltas[i][0], dy = deltas[i][1];
+      for(f = fl+dx, r = rk+dy;
+          (dx==0 || (f>=fmin && f<=fmax)) && (dy==0 || (r>=rmin && r<=rmax));
+          f += dx, r += dy) {
+        result |= (1ULL << (f + r*8));
+        if(block & (1ULL << (f + r*8))) break;
+      }
+    }
+    return result;
+  }
+
+
+  void init_between_bitboards() {
+    SquareDelta step[8] = {
+      DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
+    };
+    SignedDirection d;
+    for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
+      for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
+        BetweenBB[s1][s2] = EmptyBoardBB;
+        d = signed_direction_between_squares(s1, s2);
+        if(d != SIGNED_DIR_NONE)
+          for(Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
+            set_bit(&(BetweenBB[s1][s2]), s3);
+      }
+  }
+
+
+  Bitboard index_to_bitboard(int index, Bitboard mask) {
+    int i, j, bits = count_1s(mask);
+    Bitboard result = 0ULL;
+    for(i = 0; i < bits; i++) {
+      j = pop_1st_bit(&mask);
+      if(index & (1 << i)) result |= (1ULL << j);
+    }
+    return result;
+  }
+
+
+  void init_sliding_attacks(Bitboard attacks[],
+                            int attackIndex[], Bitboard mask[],
+                            const int shift[2], const Bitboard mult[],
+                            int deltas[][2]) {
+    int i, j, k, index = 0;
+    Bitboard b;
+    for(i = 0; i < 64; i++) {
+      attackIndex[i] = index;
+      mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);      
+      j = (1 << (64 - shift[i]));
+      for(k = 0; k < j; k++) {
+#if defined(USE_32BIT_ATTACKS)
+        b = index_to_bitboard(k, mask[i]);
+        attacks[index + 
+                 (unsigned(int(b) * int(mult[i]) ^ 
+                           int(b >> 32) * int(mult[i] >> 32)) 
+                  >> shift[i])] =
+          sliding_attacks(i, b, 4, deltas);
+#else
+        b = index_to_bitboard(k, mask[i]);
+        attacks[index + ((b * mult[i]) >> shift[i])] =
+          sliding_attacks(i, b, 4, deltas);
+#endif
+      }
+      index += j;
+    }
+  }
+  
+
+  void init_pseudo_attacks() {
+    Square s;
+    for(s = SQ_A1; s <= SQ_H8; s++) {
+      BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
+      RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
+      QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
+    }
+  }
+
+#if defined(USE_COMPACT_ROOK_ATTACKS)
+  void init_file_and_rank_attacks() {
+    int i, j, k, l, m, s;
+    Bitboard b1, b2;
+    for(i = 0; i < 64; i++) {
+
+      for(m = 0; m <= 1; m++) {
+        b1 = 0ULL;
+        for(j = 0; j < 6; j++) if(i & (1<<j)) b1 |= (1ULL << ((j+1)*(1+m*7)));
+        for(j = 0; j < 8; j++) {
+          b2 = 0ULL;
+          for(k = 0, s = 1; k < 2; k++, s *= -1) {
+            for(l = j+s; l >= 0 && l <= 7; l += s) {
+              b2 |= (m? RankBB[l] : FileBB[l]);
+              if(b1 & (1ULL << (l*(1+m*7)))) break;
+            }
+          }
+          if(m) FileAttacks[j][(b1*0xd6e8802041d0c441ULL) >> 58] = b2;
+          else RankAttacks[j][i] = b2;
+        }
+      }
+    }
+  }
+#endif // defined(USE_COMPACT_ROOK_ATTACKS)
+    
+}
diff --git a/src/bitboard.h b/src/bitboard.h
new file mode 100644 (file)
index 0000000..d9a9bf5
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(BITBOARD_H_INCLUDED)
+#define BITBOARD_H_INCLUDED
+
+
+////
+//// Defines
+////
+
+//#define USE_COMPACT_ROOK_ATTACKS
+//#define USE_32BIT_ATTACKS 
+#define USE_FOLDED_BITSCAN
+
+#define BITCOUNT_SWAR_64
+//#define BITCOUNT_SWAR_32
+//#define BITCOUNT_LOOP
+
+
+
+////
+//// Includes
+////
+
+#include "direction.h"
+#include "piece.h"
+#include "square.h"
+#include "types.h"
+
+
+////
+//// Types
+////
+
+typedef uint64_t Bitboard;
+
+
+////
+//// Constants and variables
+////
+
+const Bitboard EmptyBoardBB = 0ULL;
+
+const Bitboard WhiteSquaresBB = 0x55AA55AA55AA55AAULL;
+const Bitboard BlackSquaresBB = 0xAA55AA55AA55AA55ULL;
+
+extern const Bitboard SquaresByColorBB[2];
+
+const Bitboard FileABB = 0x0101010101010101ULL;
+const Bitboard FileBBB = 0x0202020202020202ULL;
+const Bitboard FileCBB = 0x0404040404040404ULL;
+const Bitboard FileDBB = 0x0808080808080808ULL;
+const Bitboard FileEBB = 0x1010101010101010ULL;
+const Bitboard FileFBB = 0x2020202020202020ULL;
+const Bitboard FileGBB = 0x4040404040404040ULL;
+const Bitboard FileHBB = 0x8080808080808080ULL;
+
+extern const Bitboard FileBB[8];
+extern const Bitboard NeighboringFilesBB[8];
+extern const Bitboard ThisAndNeighboringFilesBB[8];  
+
+const Bitboard Rank1BB = 0xFFULL;
+const Bitboard Rank2BB = 0xFF00ULL;
+const Bitboard Rank3BB = 0xFF0000ULL;
+const Bitboard Rank4BB = 0xFF000000ULL;
+const Bitboard Rank5BB = 0xFF00000000ULL;
+const Bitboard Rank6BB = 0xFF0000000000ULL;
+const Bitboard Rank7BB = 0xFF000000000000ULL;
+const Bitboard Rank8BB = 0xFF00000000000000ULL;
+
+extern const Bitboard RankBB[8];
+extern const Bitboard RelativeRankBB[2][8];
+extern const Bitboard InFrontBB[2][8];
+
+extern Bitboard SetMaskBB[64];
+extern Bitboard ClearMaskBB[64];
+
+extern Bitboard StepAttackBB[16][64];
+extern Bitboard RayBB[64][8];
+extern Bitboard BetweenBB[64][64];
+
+extern Bitboard PassedPawnMask[2][64];
+extern Bitboard OutpostMask[2][64];
+
+#if defined(USE_COMPACT_ROOK_ATTACKS)
+extern Bitboard RankAttacks[8][64], FileAttacks[8][64];
+#else
+extern const uint64_t RMult[64];
+extern const int RShift[64];
+extern Bitboard RMask[64];
+extern int RAttackIndex[64];
+extern Bitboard RAttacks[0x19000];
+#endif // defined(USE_COMPACT_ROOK_ATTACKS)
+
+extern const uint64_t BMult[64]; 
+extern const int BShift[64];
+extern Bitboard BMask[64];
+extern int BAttackIndex[64];
+extern Bitboard BAttacks[0x1480];
+
+extern Bitboard BishopPseudoAttacks[64];
+extern Bitboard RookPseudoAttacks[64];
+extern Bitboard QueenPseudoAttacks[64];
+
+
+////
+//// Inline functions
+////
+
+/// Functions for testing whether a given bit is set in a bitboard, and for 
+/// setting and clearing bits.
+
+inline Bitboard set_mask_bb(Square s) {
+  //  return 1ULL << s;
+  return SetMaskBB[s];
+}
+
+inline Bitboard clear_mask_bb(Square s) {
+  //  return ~set_mask_bb(s);
+  return ClearMaskBB[s];
+}
+
+inline Bitboard bit_is_set(Bitboard b, Square s) {
+  return b & set_mask_bb(s);
+}
+
+inline void set_bit(Bitboard *b, Square s) {
+  *b |= set_mask_bb(s);
+}
+
+inline void clear_bit(Bitboard *b, Square s) {
+  *b &= clear_mask_bb(s);
+}
+
+
+/// rank_bb() and file_bb() gives a bitboard containing all squares on a given
+/// file or rank.  It is also possible to pass a square as input to these
+/// functions.
+
+inline Bitboard rank_bb(Rank r) {
+  return RankBB[r];
+}
+
+inline Bitboard rank_bb(Square s) {
+  return rank_bb(square_rank(s));
+}
+
+inline Bitboard file_bb(File f) {
+  return FileBB[f];
+}
+
+inline Bitboard file_bb(Square s) {
+  return file_bb(square_file(s));
+}
+
+
+/// neighboring_files_bb takes a file or a square as input, and returns a
+/// bitboard representing all squares on the neighboring files.
+
+inline Bitboard neighboring_files_bb(File f) {
+  return NeighboringFilesBB[f];
+}
+
+inline Bitboard neighboring_files_bb(Square s) {
+  return neighboring_files_bb(square_file(s));
+}
+  
+
+/// this_and_neighboring_files_bb takes a file or a square as input, and
+/// returns a bitboard representing all squares on the given and neighboring
+/// files.
+
+inline Bitboard this_and_neighboring_files_bb(File f) {
+  return ThisAndNeighboringFilesBB[f];
+}
+
+inline Bitboard this_and_neighboring_files_bb(Square s) {
+  return this_and_neighboring_files_bb(square_file(s));
+}
+
+
+/// relative_rank_bb() takes a color and a rank as input, and returns a bitboard
+/// representing all squares on the given rank from the given color's point of
+/// view.  For instance, relative_rank_bb(WHITE, 7) gives all squares on the
+/// 7th rank, while relative_rank_bb(BLACK, 7) gives all squares on the 2nd
+/// rank.
+
+inline Bitboard relative_rank_bb(Color c, Rank r) {
+  return RelativeRankBB[c][r];
+}
+
+
+/// in_front_bb() takes a color and a rank or square as input, and returns a
+/// bitboard representing all the squares on all ranks in front of the rank
+/// (or square), from the given color's point of view.  For instance,
+/// in_front_bb(WHITE, RANK_5) will give all squares on ranks 6, 7 and 8, while
+/// in_front_bb(BLACK, SQ_D3) will give all squares on ranks 1 and 2.
+
+inline Bitboard in_front_bb(Color c, Rank r) {
+  return InFrontBB[c][r];
+}
+
+inline Bitboard in_front_bb(Color c, Square s) {
+  return in_front_bb(c, square_rank(s));
+}
+
+
+/// ray_bb() gives a bitboard representing all squares along the ray in a
+/// given direction from a given square.
+
+inline Bitboard ray_bb(Square s, SignedDirection d) {
+  return RayBB[s][d];
+}
+
+
+/// Functions for computing sliding attack bitboards.  rook_attacks_bb(),
+/// bishop_attacks_bb() and queen_attacks_bb() all take a square and a
+/// bitboard of occupied squares as input, and return a bitboard representing
+/// all squares attacked by a rook, bishop or queen on the given square.
+
+#if defined(USE_COMPACT_ROOK_ATTACKS)
+
+inline Bitboard file_attacks_bb(Square s, Bitboard blockers) {
+  Bitboard b = (blockers >> square_file(s)) & 0x01010101010100ULL;
+  return
+    FileAttacks[square_rank(s)][(b*0xd6e8802041d0c441ULL)>>58] & file_bb(s);
+}
+
+inline Bitboard rank_attacks_bb(Square s, Bitboard blockers) {
+  Bitboard b = (blockers >> ((s & 56) + 1)) & 63;
+  return RankAttacks[square_file(s)][b] & rank_bb(s);
+}
+
+inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
+  return file_attacks_bb(s, blockers) | rank_attacks_bb(s, blockers);
+}
+
+#elif defined(USE_32BIT_ATTACKS)
+
+inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
+  Bitboard b = blockers & RMask[s];
+  return RAttacks[RAttackIndex[s] + 
+                  (unsigned(int(b) * int(RMult[s]) ^
+                            int(b >> 32) * int(RMult[s] >> 32)) 
+                   >> RShift[s])];
+}
+
+#else
+
+inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
+  Bitboard b = blockers & RMask[s];
+  return RAttacks[RAttackIndex[s] + ((b * RMult[s]) >> RShift[s])];
+}
+
+#endif
+
+#if defined(USE_32BIT_ATTACKS)
+
+inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
+  Bitboard b = blockers & BMask[s];
+  return BAttacks[BAttackIndex[s] + 
+                  (unsigned(int(b) * int(BMult[s]) ^
+                            int(b >> 32) * int(BMult[s] >> 32)) 
+                   >> BShift[s])];
+}
+
+#else // defined(USE_32BIT_ATTACKS)
+
+inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
+  Bitboard b = blockers & BMask[s];
+  return BAttacks[BAttackIndex[s] + ((b * BMult[s]) >> BShift[s])];
+}
+
+#endif // defined(USE_32BIT_ATTACKS)
+
+inline Bitboard queen_attacks_bb(Square s, Bitboard blockers) {
+  return rook_attacks_bb(s, blockers) | bishop_attacks_bb(s, blockers);
+}
+
+
+/// squares_between returns a bitboard representing all squares between
+/// two squares.  For instance, squares_between(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 line, file or diagonal, EmptyBoardBB is returned.
+
+inline Bitboard squares_between(Square s1, Square s2) {
+  return BetweenBB[s1][s2];
+}
+
+
+/// squares_in_front_of takes a color and a square as input, and returns a 
+/// bitboard representing all squares along the line in front of the square,
+/// from the point of view of the given color.  For instance, 
+/// squares_in_front_of(BLACK, SQ_E4) returns a bitboard with the squares
+/// e3, e2 and e1 set.
+
+inline Bitboard squares_in_front_of(Color c, Square s) {
+  return in_front_bb(c, s) & file_bb(s);
+}
+
+
+/// squares_behind is similar to squares_in_front, but returns the squares
+/// behind the square instead of in front of the square.
+
+inline Bitboard squares_behind(Color c, Square s) {
+  return in_front_bb(opposite_color(c), s) & file_bb(s);
+}
+
+
+/// 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.
+
+inline Bitboard passed_pawn_mask(Color c, Square s) {
+  return PassedPawnMask[c][s];
+}
+
+
+/// outpost_mask takes a color and a square as input, and returns a bitboard
+/// mask which can be used to test whether a piece on the square can possibly
+/// be driven away by an enemy pawn.
+
+inline Bitboard outpost_mask(Color c, Square s) {
+  return OutpostMask[c][s];
+}
+
+
+/// isolated_pawn_mask takes a square as input, and returns a bitboard mask 
+/// which can be used to test whether a pawn on the given square is isolated.
+
+inline Bitboard isolated_pawn_mask(Square s) {
+  return neighboring_files_bb(s);
+}
+
+
+/// count_1s() counts the number of nonzero bits in a bitboard.
+
+#if defined(BITCOUNT_LOOP)
+
+inline int count_1s(Bitboard b) {
+  int r;
+  for(r = 0; b; r++, b &= b - 1);
+  return r;
+}
+
+inline int count_1s_max_15(Bitboard b) {
+  return count_1s(b);
+}
+
+#elif defined(BITCOUNT_SWAR_32)
+
+inline int count_1s(Bitboard b) {
+  unsigned w = unsigned(b >> 32), v = unsigned(b);
+  v = v - ((v >> 1) & 0x55555555);
+  w = w - ((w >> 1) & 0x55555555);
+  v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+  w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
+  v = (v + (v >> 4)) & 0x0F0F0F0F;
+  w = (w + (w >> 4)) & 0x0F0F0F0F;
+  v = ((v+w) * 0x01010101) >> 24; // mul is fast on amd procs
+  return int(v);
+}
+
+inline int count_1s_max_15(Bitboard b) {
+  unsigned w = unsigned(b >> 32), v = unsigned(b);
+  v = v - ((v >> 1) & 0x55555555);
+  w = w - ((w >> 1) & 0x55555555);
+  v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+  w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
+  v = ((v+w) * 0x11111111) >> 28;
+  return int(v);
+}
+
+#elif defined(BITCOUNT_SWAR_64)
+
+inline int count_1s(Bitboard b) {
+  b -= ((b>>1) & 0x5555555555555555ULL);
+  b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
+  b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
+  b *= 0x0101010101010101ULL;
+  return int(b >> 56);
+}
+
+inline int count_1s_max_15(Bitboard b) {
+  b -= (b>>1) & 0x5555555555555555ULL;
+  b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
+  b *= 0x1111111111111111ULL;
+  return int(b >> 60);
+}
+
+#endif // BITCOUNT
+
+
+////
+//// Prototypes
+////
+
+extern void print_bitboard(Bitboard b);
+extern void init_bitboards();
+extern Square first_1(Bitboard b);
+extern Square pop_1st_bit(Bitboard *b);
+
+
+#endif // !defined(BITBOARD_H_INCLUDED)
diff --git a/src/book.cpp b/src/book.cpp
new file mode 100644 (file)
index 0000000..bd2f481
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung 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/>.
+*/
+
+
+/*
+  The code in this file is based on the opening book code in PolyGlot
+  by Fabien Letouzey.  PolyGlot is available under the GNU General
+  Public License, and can be downloaded from http://wbec-ridderkerk.nl
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+#include <cstdio>
+
+#include "book.h"
+#include "mersenne.h"
+#include "movegen.h"
+
+
+////
+//// Global variables
+////
+
+Book OpeningBook;
+
+
+////
+//// Local definitions
+////
+
+namespace {
+
+  /// Random numbers from PolyGlot, used to compute book hash keys.
+
+  const uint64_t Random64[781] = {
+    0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
+    0x9C15F73E62A76AE2ULL, 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL,
+    0x0FBBAD1F61042279ULL, 0xE83A908FF2FB60CAULL, 0x0D7E765D58755C10ULL,
+    0x1A083822CEAFE02DULL, 0x9605D5F0E25EC3B0ULL, 0xD021FF5CD13A2ED5ULL,
+    0x40BDF15D4A672E32ULL, 0x011355146FD56395ULL, 0x5DB4832046F3D9E5ULL,
+    0x239F8B2D7FF719CCULL, 0x05D1A1AE85B49AA1ULL, 0x679F848F6E8FC971ULL,
+    0x7449BBFF801FED0BULL, 0x7D11CDB1C3B7ADF0ULL, 0x82C7709E781EB7CCULL,
+    0xF3218F1C9510786CULL, 0x331478F3AF51BBE6ULL, 0x4BB38DE5E7219443ULL,
+    0xAA649C6EBCFD50FCULL, 0x8DBD98A352AFD40BULL, 0x87D2074B81D79217ULL,
+    0x19F3C751D3E92AE1ULL, 0xB4AB30F062B19ABFULL, 0x7B0500AC42047AC4ULL,
+    0xC9452CA81A09D85DULL, 0x24AA6C514DA27500ULL, 0x4C9F34427501B447ULL,
+    0x14A68FD73C910841ULL, 0xA71B9B83461CBD93ULL, 0x03488B95B0F1850FULL,
+    0x637B2B34FF93C040ULL, 0x09D1BC9A3DD90A94ULL, 0x3575668334A1DD3BULL,
+    0x735E2B97A4C45A23ULL, 0x18727070F1BD400BULL, 0x1FCBACD259BF02E7ULL,
+    0xD310A7C2CE9B6555ULL, 0xBF983FE0FE5D8244ULL, 0x9F74D14F7454A824ULL,
+    0x51EBDC4AB9BA3035ULL, 0x5C82C505DB9AB0FAULL, 0xFCF7FE8A3430B241ULL,
+    0x3253A729B9BA3DDEULL, 0x8C74C368081B3075ULL, 0xB9BC6C87167C33E7ULL,
+    0x7EF48F2B83024E20ULL, 0x11D505D4C351BD7FULL, 0x6568FCA92C76A243ULL,
+    0x4DE0B0F40F32A7B8ULL, 0x96D693460CC37E5DULL, 0x42E240CB63689F2FULL,
+    0x6D2BDCDAE2919661ULL, 0x42880B0236E4D951ULL, 0x5F0F4A5898171BB6ULL,
+    0x39F890F579F92F88ULL, 0x93C5B5F47356388BULL, 0x63DC359D8D231B78ULL,
+    0xEC16CA8AEA98AD76ULL, 0x5355F900C2A82DC7ULL, 0x07FB9F855A997142ULL,
+    0x5093417AA8A7ED5EULL, 0x7BCBC38DA25A7F3CULL, 0x19FC8A768CF4B6D4ULL,
+    0x637A7780DECFC0D9ULL, 0x8249A47AEE0E41F7ULL, 0x79AD695501E7D1E8ULL,
+    0x14ACBAF4777D5776ULL, 0xF145B6BECCDEA195ULL, 0xDABF2AC8201752FCULL,
+    0x24C3C94DF9C8D3F6ULL, 0xBB6E2924F03912EAULL, 0x0CE26C0B95C980D9ULL,
+    0xA49CD132BFBF7CC4ULL, 0xE99D662AF4243939ULL, 0x27E6AD7891165C3FULL,
+    0x8535F040B9744FF1ULL, 0x54B3F4FA5F40D873ULL, 0x72B12C32127FED2BULL,
+    0xEE954D3C7B411F47ULL, 0x9A85AC909A24EAA1ULL, 0x70AC4CD9F04F21F5ULL,
+    0xF9B89D3E99A075C2ULL, 0x87B3E2B2B5C907B1ULL, 0xA366E5B8C54F48B8ULL,
+    0xAE4A9346CC3F7CF2ULL, 0x1920C04D47267BBDULL, 0x87BF02C6B49E2AE9ULL,
+    0x092237AC237F3859ULL, 0xFF07F64EF8ED14D0ULL, 0x8DE8DCA9F03CC54EULL,
+    0x9C1633264DB49C89ULL, 0xB3F22C3D0B0B38EDULL, 0x390E5FB44D01144BULL,
+    0x5BFEA5B4712768E9ULL, 0x1E1032911FA78984ULL, 0x9A74ACB964E78CB3ULL,
+    0x4F80F7A035DAFB04ULL, 0x6304D09A0B3738C4ULL, 0x2171E64683023A08ULL,
+    0x5B9B63EB9CEFF80CULL, 0x506AACF489889342ULL, 0x1881AFC9A3A701D6ULL,
+    0x6503080440750644ULL, 0xDFD395339CDBF4A7ULL, 0xEF927DBCF00C20F2ULL,
+    0x7B32F7D1E03680ECULL, 0xB9FD7620E7316243ULL, 0x05A7E8A57DB91B77ULL,
+    0xB5889C6E15630A75ULL, 0x4A750A09CE9573F7ULL, 0xCF464CEC899A2F8AULL,
+    0xF538639CE705B824ULL, 0x3C79A0FF5580EF7FULL, 0xEDE6C87F8477609DULL,
+    0x799E81F05BC93F31ULL, 0x86536B8CF3428A8CULL, 0x97D7374C60087B73ULL,
+    0xA246637CFF328532ULL, 0x043FCAE60CC0EBA0ULL, 0x920E449535DD359EULL,
+    0x70EB093B15B290CCULL, 0x73A1921916591CBDULL, 0x56436C9FE1A1AA8DULL,
+    0xEFAC4B70633B8F81ULL, 0xBB215798D45DF7AFULL, 0x45F20042F24F1768ULL,
+    0x930F80F4E8EB7462ULL, 0xFF6712FFCFD75EA1ULL, 0xAE623FD67468AA70ULL,
+    0xDD2C5BC84BC8D8FCULL, 0x7EED120D54CF2DD9ULL, 0x22FE545401165F1CULL,
+    0xC91800E98FB99929ULL, 0x808BD68E6AC10365ULL, 0xDEC468145B7605F6ULL,
+    0x1BEDE3A3AEF53302ULL, 0x43539603D6C55602ULL, 0xAA969B5C691CCB7AULL,
+    0xA87832D392EFEE56ULL, 0x65942C7B3C7E11AEULL, 0xDED2D633CAD004F6ULL,
+    0x21F08570F420E565ULL, 0xB415938D7DA94E3CULL, 0x91B859E59ECB6350ULL,
+    0x10CFF333E0ED804AULL, 0x28AED140BE0BB7DDULL, 0xC5CC1D89724FA456ULL,
+    0x5648F680F11A2741ULL, 0x2D255069F0B7DAB3ULL, 0x9BC5A38EF729ABD4ULL,
+    0xEF2F054308F6A2BCULL, 0xAF2042F5CC5C2858ULL, 0x480412BAB7F5BE2AULL,
+    0xAEF3AF4A563DFE43ULL, 0x19AFE59AE451497FULL, 0x52593803DFF1E840ULL,
+    0xF4F076E65F2CE6F0ULL, 0x11379625747D5AF3ULL, 0xBCE5D2248682C115ULL,
+    0x9DA4243DE836994FULL, 0x066F70B33FE09017ULL, 0x4DC4DE189B671A1CULL,
+    0x51039AB7712457C3ULL, 0xC07A3F80C31FB4B4ULL, 0xB46EE9C5E64A6E7CULL,
+    0xB3819A42ABE61C87ULL, 0x21A007933A522A20ULL, 0x2DF16F761598AA4FULL,
+    0x763C4A1371B368FDULL, 0xF793C46702E086A0ULL, 0xD7288E012AEB8D31ULL,
+    0xDE336A2A4BC1C44BULL, 0x0BF692B38D079F23ULL, 0x2C604A7A177326B3ULL,
+    0x4850E73E03EB6064ULL, 0xCFC447F1E53C8E1BULL, 0xB05CA3F564268D99ULL,
+    0x9AE182C8BC9474E8ULL, 0xA4FC4BD4FC5558CAULL, 0xE755178D58FC4E76ULL,
+    0x69B97DB1A4C03DFEULL, 0xF9B5B7C4ACC67C96ULL, 0xFC6A82D64B8655FBULL,
+    0x9C684CB6C4D24417ULL, 0x8EC97D2917456ED0ULL, 0x6703DF9D2924E97EULL,
+    0xC547F57E42A7444EULL, 0x78E37644E7CAD29EULL, 0xFE9A44E9362F05FAULL,
+    0x08BD35CC38336615ULL, 0x9315E5EB3A129ACEULL, 0x94061B871E04DF75ULL,
+    0xDF1D9F9D784BA010ULL, 0x3BBA57B68871B59DULL, 0xD2B7ADEEDED1F73FULL,
+    0xF7A255D83BC373F8ULL, 0xD7F4F2448C0CEB81ULL, 0xD95BE88CD210FFA7ULL,
+    0x336F52F8FF4728E7ULL, 0xA74049DAC312AC71ULL, 0xA2F61BB6E437FDB5ULL,
+    0x4F2A5CB07F6A35B3ULL, 0x87D380BDA5BF7859ULL, 0x16B9F7E06C453A21ULL,
+    0x7BA2484C8A0FD54EULL, 0xF3A678CAD9A2E38CULL, 0x39B0BF7DDE437BA2ULL,
+    0xFCAF55C1BF8A4424ULL, 0x18FCF680573FA594ULL, 0x4C0563B89F495AC3ULL,
+    0x40E087931A00930DULL, 0x8CFFA9412EB642C1ULL, 0x68CA39053261169FULL,
+    0x7A1EE967D27579E2ULL, 0x9D1D60E5076F5B6FULL, 0x3810E399B6F65BA2ULL,
+    0x32095B6D4AB5F9B1ULL, 0x35CAB62109DD038AULL, 0xA90B24499FCFAFB1ULL,
+    0x77A225A07CC2C6BDULL, 0x513E5E634C70E331ULL, 0x4361C0CA3F692F12ULL,
+    0xD941ACA44B20A45BULL, 0x528F7C8602C5807BULL, 0x52AB92BEB9613989ULL,
+    0x9D1DFA2EFC557F73ULL, 0x722FF175F572C348ULL, 0x1D1260A51107FE97ULL,
+    0x7A249A57EC0C9BA2ULL, 0x04208FE9E8F7F2D6ULL, 0x5A110C6058B920A0ULL,
+    0x0CD9A497658A5698ULL, 0x56FD23C8F9715A4CULL, 0x284C847B9D887AAEULL,
+    0x04FEABFBBDB619CBULL, 0x742E1E651C60BA83ULL, 0x9A9632E65904AD3CULL,
+    0x881B82A13B51B9E2ULL, 0x506E6744CD974924ULL, 0xB0183DB56FFC6A79ULL,
+    0x0ED9B915C66ED37EULL, 0x5E11E86D5873D484ULL, 0xF678647E3519AC6EULL,
+    0x1B85D488D0F20CC5ULL, 0xDAB9FE6525D89021ULL, 0x0D151D86ADB73615ULL,
+    0xA865A54EDCC0F019ULL, 0x93C42566AEF98FFBULL, 0x99E7AFEABE000731ULL,
+    0x48CBFF086DDF285AULL, 0x7F9B6AF1EBF78BAFULL, 0x58627E1A149BBA21ULL,
+    0x2CD16E2ABD791E33ULL, 0xD363EFF5F0977996ULL, 0x0CE2A38C344A6EEDULL,
+    0x1A804AADB9CFA741ULL, 0x907F30421D78C5DEULL, 0x501F65EDB3034D07ULL,
+    0x37624AE5A48FA6E9ULL, 0x957BAF61700CFF4EULL, 0x3A6C27934E31188AULL,
+    0xD49503536ABCA345ULL, 0x088E049589C432E0ULL, 0xF943AEE7FEBF21B8ULL,
+    0x6C3B8E3E336139D3ULL, 0x364F6FFA464EE52EULL, 0xD60F6DCEDC314222ULL,
+    0x56963B0DCA418FC0ULL, 0x16F50EDF91E513AFULL, 0xEF1955914B609F93ULL,
+    0x565601C0364E3228ULL, 0xECB53939887E8175ULL, 0xBAC7A9A18531294BULL,
+    0xB344C470397BBA52ULL, 0x65D34954DAF3CEBDULL, 0xB4B81B3FA97511E2ULL,
+    0xB422061193D6F6A7ULL, 0x071582401C38434DULL, 0x7A13F18BBEDC4FF5ULL,
+    0xBC4097B116C524D2ULL, 0x59B97885E2F2EA28ULL, 0x99170A5DC3115544ULL,
+    0x6F423357E7C6A9F9ULL, 0x325928EE6E6F8794ULL, 0xD0E4366228B03343ULL,
+    0x565C31F7DE89EA27ULL, 0x30F5611484119414ULL, 0xD873DB391292ED4FULL,
+    0x7BD94E1D8E17DEBCULL, 0xC7D9F16864A76E94ULL, 0x947AE053EE56E63CULL,
+    0xC8C93882F9475F5FULL, 0x3A9BF55BA91F81CAULL, 0xD9A11FBB3D9808E4ULL,
+    0x0FD22063EDC29FCAULL, 0xB3F256D8ACA0B0B9ULL, 0xB03031A8B4516E84ULL,
+    0x35DD37D5871448AFULL, 0xE9F6082B05542E4EULL, 0xEBFAFA33D7254B59ULL,
+    0x9255ABB50D532280ULL, 0xB9AB4CE57F2D34F3ULL, 0x693501D628297551ULL,
+    0xC62C58F97DD949BFULL, 0xCD454F8F19C5126AULL, 0xBBE83F4ECC2BDECBULL,
+    0xDC842B7E2819E230ULL, 0xBA89142E007503B8ULL, 0xA3BC941D0A5061CBULL,
+    0xE9F6760E32CD8021ULL, 0x09C7E552BC76492FULL, 0x852F54934DA55CC9ULL,
+    0x8107FCCF064FCF56ULL, 0x098954D51FFF6580ULL, 0x23B70EDB1955C4BFULL,
+    0xC330DE426430F69DULL, 0x4715ED43E8A45C0AULL, 0xA8D7E4DAB780A08DULL,
+    0x0572B974F03CE0BBULL, 0xB57D2E985E1419C7ULL, 0xE8D9ECBE2CF3D73FULL,
+    0x2FE4B17170E59750ULL, 0x11317BA87905E790ULL, 0x7FBF21EC8A1F45ECULL,
+    0x1725CABFCB045B00ULL, 0x964E915CD5E2B207ULL, 0x3E2B8BCBF016D66DULL,
+    0xBE7444E39328A0ACULL, 0xF85B2B4FBCDE44B7ULL, 0x49353FEA39BA63B1ULL,
+    0x1DD01AAFCD53486AULL, 0x1FCA8A92FD719F85ULL, 0xFC7C95D827357AFAULL,
+    0x18A6A990C8B35EBDULL, 0xCCCB7005C6B9C28DULL, 0x3BDBB92C43B17F26ULL,
+    0xAA70B5B4F89695A2ULL, 0xE94C39A54A98307FULL, 0xB7A0B174CFF6F36EULL,
+    0xD4DBA84729AF48ADULL, 0x2E18BC1AD9704A68ULL, 0x2DE0966DAF2F8B1CULL,
+    0xB9C11D5B1E43A07EULL, 0x64972D68DEE33360ULL, 0x94628D38D0C20584ULL,
+    0xDBC0D2B6AB90A559ULL, 0xD2733C4335C6A72FULL, 0x7E75D99D94A70F4DULL,
+    0x6CED1983376FA72BULL, 0x97FCAACBF030BC24ULL, 0x7B77497B32503B12ULL,
+    0x8547EDDFB81CCB94ULL, 0x79999CDFF70902CBULL, 0xCFFE1939438E9B24ULL,
+    0x829626E3892D95D7ULL, 0x92FAE24291F2B3F1ULL, 0x63E22C147B9C3403ULL,
+    0xC678B6D860284A1CULL, 0x5873888850659AE7ULL, 0x0981DCD296A8736DULL,
+    0x9F65789A6509A440ULL, 0x9FF38FED72E9052FULL, 0xE479EE5B9930578CULL,
+    0xE7F28ECD2D49EECDULL, 0x56C074A581EA17FEULL, 0x5544F7D774B14AEFULL,
+    0x7B3F0195FC6F290FULL, 0x12153635B2C0CF57ULL, 0x7F5126DBBA5E0CA7ULL,
+    0x7A76956C3EAFB413ULL, 0x3D5774A11D31AB39ULL, 0x8A1B083821F40CB4ULL,
+    0x7B4A38E32537DF62ULL, 0x950113646D1D6E03ULL, 0x4DA8979A0041E8A9ULL,
+    0x3BC36E078F7515D7ULL, 0x5D0A12F27AD310D1ULL, 0x7F9D1A2E1EBE1327ULL,
+    0xDA3A361B1C5157B1ULL, 0xDCDD7D20903D0C25ULL, 0x36833336D068F707ULL,
+    0xCE68341F79893389ULL, 0xAB9090168DD05F34ULL, 0x43954B3252DC25E5ULL,
+    0xB438C2B67F98E5E9ULL, 0x10DCD78E3851A492ULL, 0xDBC27AB5447822BFULL,
+    0x9B3CDB65F82CA382ULL, 0xB67B7896167B4C84ULL, 0xBFCED1B0048EAC50ULL,
+    0xA9119B60369FFEBDULL, 0x1FFF7AC80904BF45ULL, 0xAC12FB171817EEE7ULL,
+    0xAF08DA9177DDA93DULL, 0x1B0CAB936E65C744ULL, 0xB559EB1D04E5E932ULL,
+    0xC37B45B3F8D6F2BAULL, 0xC3A9DC228CAAC9E9ULL, 0xF3B8B6675A6507FFULL,
+    0x9FC477DE4ED681DAULL, 0x67378D8ECCEF96CBULL, 0x6DD856D94D259236ULL,
+    0xA319CE15B0B4DB31ULL, 0x073973751F12DD5EULL, 0x8A8E849EB32781A5ULL,
+    0xE1925C71285279F5ULL, 0x74C04BF1790C0EFEULL, 0x4DDA48153C94938AULL,
+    0x9D266D6A1CC0542CULL, 0x7440FB816508C4FEULL, 0x13328503DF48229FULL,
+    0xD6BF7BAEE43CAC40ULL, 0x4838D65F6EF6748FULL, 0x1E152328F3318DEAULL,
+    0x8F8419A348F296BFULL, 0x72C8834A5957B511ULL, 0xD7A023A73260B45CULL,
+    0x94EBC8ABCFB56DAEULL, 0x9FC10D0F989993E0ULL, 0xDE68A2355B93CAE6ULL,
+    0xA44CFE79AE538BBEULL, 0x9D1D84FCCE371425ULL, 0x51D2B1AB2DDFB636ULL,
+    0x2FD7E4B9E72CD38CULL, 0x65CA5B96B7552210ULL, 0xDD69A0D8AB3B546DULL,
+    0x604D51B25FBF70E2ULL, 0x73AA8A564FB7AC9EULL, 0x1A8C1E992B941148ULL,
+    0xAAC40A2703D9BEA0ULL, 0x764DBEAE7FA4F3A6ULL, 0x1E99B96E70A9BE8BULL,
+    0x2C5E9DEB57EF4743ULL, 0x3A938FEE32D29981ULL, 0x26E6DB8FFDF5ADFEULL,
+    0x469356C504EC9F9DULL, 0xC8763C5B08D1908CULL, 0x3F6C6AF859D80055ULL,
+    0x7F7CC39420A3A545ULL, 0x9BFB227EBDF4C5CEULL, 0x89039D79D6FC5C5CULL,
+    0x8FE88B57305E2AB6ULL, 0xA09E8C8C35AB96DEULL, 0xFA7E393983325753ULL,
+    0xD6B6D0ECC617C699ULL, 0xDFEA21EA9E7557E3ULL, 0xB67C1FA481680AF8ULL,
+    0xCA1E3785A9E724E5ULL, 0x1CFC8BED0D681639ULL, 0xD18D8549D140CAEAULL,
+    0x4ED0FE7E9DC91335ULL, 0xE4DBF0634473F5D2ULL, 0x1761F93A44D5AEFEULL,
+    0x53898E4C3910DA55ULL, 0x734DE8181F6EC39AULL, 0x2680B122BAA28D97ULL,
+    0x298AF231C85BAFABULL, 0x7983EED3740847D5ULL, 0x66C1A2A1A60CD889ULL,
+    0x9E17E49642A3E4C1ULL, 0xEDB454E7BADC0805ULL, 0x50B704CAB602C329ULL,
+    0x4CC317FB9CDDD023ULL, 0x66B4835D9EAFEA22ULL, 0x219B97E26FFC81BDULL,
+    0x261E4E4C0A333A9DULL, 0x1FE2CCA76517DB90ULL, 0xD7504DFA8816EDBBULL,
+    0xB9571FA04DC089C8ULL, 0x1DDC0325259B27DEULL, 0xCF3F4688801EB9AAULL,
+    0xF4F5D05C10CAB243ULL, 0x38B6525C21A42B0EULL, 0x36F60E2BA4FA6800ULL,
+    0xEB3593803173E0CEULL, 0x9C4CD6257C5A3603ULL, 0xAF0C317D32ADAA8AULL,
+    0x258E5A80C7204C4BULL, 0x8B889D624D44885DULL, 0xF4D14597E660F855ULL,
+    0xD4347F66EC8941C3ULL, 0xE699ED85B0DFB40DULL, 0x2472F6207C2D0484ULL,
+    0xC2A1E7B5B459AEB5ULL, 0xAB4F6451CC1D45ECULL, 0x63767572AE3D6174ULL,
+    0xA59E0BD101731A28ULL, 0x116D0016CB948F09ULL, 0x2CF9C8CA052F6E9FULL,
+    0x0B090A7560A968E3ULL, 0xABEEDDB2DDE06FF1ULL, 0x58EFC10B06A2068DULL,
+    0xC6E57A78FBD986E0ULL, 0x2EAB8CA63CE802D7ULL, 0x14A195640116F336ULL,
+    0x7C0828DD624EC390ULL, 0xD74BBE77E6116AC7ULL, 0x804456AF10F5FB53ULL,
+    0xEBE9EA2ADF4321C7ULL, 0x03219A39EE587A30ULL, 0x49787FEF17AF9924ULL,
+    0xA1E9300CD8520548ULL, 0x5B45E522E4B1B4EFULL, 0xB49C3B3995091A36ULL,
+    0xD4490AD526F14431ULL, 0x12A8F216AF9418C2ULL, 0x001F837CC7350524ULL,
+    0x1877B51E57A764D5ULL, 0xA2853B80F17F58EEULL, 0x993E1DE72D36D310ULL,
+    0xB3598080CE64A656ULL, 0x252F59CF0D9F04BBULL, 0xD23C8E176D113600ULL,
+    0x1BDA0492E7E4586EULL, 0x21E0BD5026C619BFULL, 0x3B097ADAF088F94EULL,
+    0x8D14DEDB30BE846EULL, 0xF95CFFA23AF5F6F4ULL, 0x3871700761B3F743ULL,
+    0xCA672B91E9E4FA16ULL, 0x64C8E531BFF53B55ULL, 0x241260ED4AD1E87DULL,
+    0x106C09B972D2E822ULL, 0x7FBA195410E5CA30ULL, 0x7884D9BC6CB569D8ULL,
+    0x0647DFEDCD894A29ULL, 0x63573FF03E224774ULL, 0x4FC8E9560F91B123ULL,
+    0x1DB956E450275779ULL, 0xB8D91274B9E9D4FBULL, 0xA2EBEE47E2FBFCE1ULL,
+    0xD9F1F30CCD97FB09ULL, 0xEFED53D75FD64E6BULL, 0x2E6D02C36017F67FULL,
+    0xA9AA4D20DB084E9BULL, 0xB64BE8D8B25396C1ULL, 0x70CB6AF7C2D5BCF0ULL,
+    0x98F076A4F7A2322EULL, 0xBF84470805E69B5FULL, 0x94C3251F06F90CF3ULL,
+    0x3E003E616A6591E9ULL, 0xB925A6CD0421AFF3ULL, 0x61BDD1307C66E300ULL,
+    0xBF8D5108E27E0D48ULL, 0x240AB57A8B888B20ULL, 0xFC87614BAF287E07ULL,
+    0xEF02CDD06FFDB432ULL, 0xA1082C0466DF6C0AULL, 0x8215E577001332C8ULL,
+    0xD39BB9C3A48DB6CFULL, 0x2738259634305C14ULL, 0x61CF4F94C97DF93DULL,
+    0x1B6BACA2AE4E125BULL, 0x758F450C88572E0BULL, 0x959F587D507A8359ULL,
+    0xB063E962E045F54DULL, 0x60E8ED72C0DFF5D1ULL, 0x7B64978555326F9FULL,
+    0xFD080D236DA814BAULL, 0x8C90FD9B083F4558ULL, 0x106F72FE81E2C590ULL,
+    0x7976033A39F7D952ULL, 0xA4EC0132764CA04BULL, 0x733EA705FAE4FA77ULL,
+    0xB4D8F77BC3E56167ULL, 0x9E21F4F903B33FD9ULL, 0x9D765E419FB69F6DULL,
+    0xD30C088BA61EA5EFULL, 0x5D94337FBFAF7F5BULL, 0x1A4E4822EB4D7A59ULL,
+    0x6FFE73E81B637FB3ULL, 0xDDF957BC36D8B9CAULL, 0x64D0E29EEA8838B3ULL,
+    0x08DD9BDFD96B9F63ULL, 0x087E79E5A57D1D13ULL, 0xE328E230E3E2B3FBULL,
+    0x1C2559E30F0946BEULL, 0x720BF5F26F4D2EAAULL, 0xB0774D261CC609DBULL,
+    0x443F64EC5A371195ULL, 0x4112CF68649A260EULL, 0xD813F2FAB7F5C5CAULL,
+    0x660D3257380841EEULL, 0x59AC2C7873F910A3ULL, 0xE846963877671A17ULL,
+    0x93B633ABFA3469F8ULL, 0xC0C0F5A60EF4CDCFULL, 0xCAF21ECD4377B28CULL,
+    0x57277707199B8175ULL, 0x506C11B9D90E8B1DULL, 0xD83CC2687A19255FULL,
+    0x4A29C6465A314CD1ULL, 0xED2DF21216235097ULL, 0xB5635C95FF7296E2ULL,
+    0x22AF003AB672E811ULL, 0x52E762596BF68235ULL, 0x9AEBA33AC6ECC6B0ULL,
+    0x944F6DE09134DFB6ULL, 0x6C47BEC883A7DE39ULL, 0x6AD047C430A12104ULL,
+    0xA5B1CFDBA0AB4067ULL, 0x7C45D833AFF07862ULL, 0x5092EF950A16DA0BULL,
+    0x9338E69C052B8E7BULL, 0x455A4B4CFE30E3F5ULL, 0x6B02E63195AD0CF8ULL,
+    0x6B17B224BAD6BF27ULL, 0xD1E0CCD25BB9C169ULL, 0xDE0C89A556B9AE70ULL,
+    0x50065E535A213CF6ULL, 0x9C1169FA2777B874ULL, 0x78EDEFD694AF1EEDULL,
+    0x6DC93D9526A50E68ULL, 0xEE97F453F06791EDULL, 0x32AB0EDB696703D3ULL,
+    0x3A6853C7E70757A7ULL, 0x31865CED6120F37DULL, 0x67FEF95D92607890ULL,
+    0x1F2B1D1F15F6DC9CULL, 0xB69E38A8965C6B65ULL, 0xAA9119FF184CCCF4ULL,
+    0xF43C732873F24C13ULL, 0xFB4A3D794A9A80D2ULL, 0x3550C2321FD6109CULL,
+    0x371F77E76BB8417EULL, 0x6BFA9AAE5EC05779ULL, 0xCD04F3FF001A4778ULL,
+    0xE3273522064480CAULL, 0x9F91508BFFCFC14AULL, 0x049A7F41061A9E60ULL,
+    0xFCB6BE43A9F2FE9BULL, 0x08DE8A1C7797DA9BULL, 0x8F9887E6078735A1ULL,
+    0xB5B4071DBFC73A66ULL, 0x230E343DFBA08D33ULL, 0x43ED7F5A0FAE657DULL,
+    0x3A88A0FBBCB05C63ULL, 0x21874B8B4D2DBC4FULL, 0x1BDEA12E35F6A8C9ULL,
+    0x53C065C6C8E63528ULL, 0xE34A1D250E7A8D6BULL, 0xD6B04D3B7651DD7EULL,
+    0x5E90277E7CB39E2DULL, 0x2C046F22062DC67DULL, 0xB10BB459132D0A26ULL,
+    0x3FA9DDFB67E2F199ULL, 0x0E09B88E1914F7AFULL, 0x10E8B35AF3EEAB37ULL,
+    0x9EEDECA8E272B933ULL, 0xD4C718BC4AE8AE5FULL, 0x81536D601170FC20ULL,
+    0x91B534F885818A06ULL, 0xEC8177F83F900978ULL, 0x190E714FADA5156EULL,
+    0xB592BF39B0364963ULL, 0x89C350C893AE7DC1ULL, 0xAC042E70F8B383F2ULL,
+    0xB49B52E587A1EE60ULL, 0xFB152FE3FF26DA89ULL, 0x3E666E6F69AE2C15ULL,
+    0x3B544EBE544C19F9ULL, 0xE805A1E290CF2456ULL, 0x24B33C9D7ED25117ULL,
+    0xE74733427B72F0C1ULL, 0x0A804D18B7097475ULL, 0x57E3306D881EDB4FULL,
+    0x4AE7D6A36EB5DBCBULL, 0x2D8D5432157064C8ULL, 0xD1E649DE1E7F268BULL,
+    0x8A328A1CEDFE552CULL, 0x07A3AEC79624C7DAULL, 0x84547DDC3E203C94ULL,
+    0x990A98FD5071D263ULL, 0x1A4FF12616EEFC89ULL, 0xF6F7FD1431714200ULL,
+    0x30C05B1BA332F41CULL, 0x8D2636B81555A786ULL, 0x46C9FEB55D120902ULL,
+    0xCCEC0A73B49C9921ULL, 0x4E9D2827355FC492ULL, 0x19EBB029435DCB0FULL,
+    0x4659D2B743848A2CULL, 0x963EF2C96B33BE31ULL, 0x74F85198B05A2E7DULL,
+    0x5A0F544DD2B1FB18ULL, 0x03727073C2E134B1ULL, 0xC7F6AA2DE59AEA61ULL,
+    0x352787BAA0D7C22FULL, 0x9853EAB63B5E0B35ULL, 0xABBDCDD7ED5C0860ULL,
+    0xCF05DAF5AC8D77B0ULL, 0x49CAD48CEBF4A71EULL, 0x7A4C10EC2158C4A6ULL,
+    0xD9E92AA246BF719EULL, 0x13AE978D09FE5557ULL, 0x730499AF921549FFULL,
+    0x4E4B705B92903BA4ULL, 0xFF577222C14F0A3AULL, 0x55B6344CF97AAFAEULL,
+    0xB862225B055B6960ULL, 0xCAC09AFBDDD2CDB4ULL, 0xDAF8E9829FE96B5FULL,
+    0xB5FDFC5D3132C498ULL, 0x310CB380DB6F7503ULL, 0xE87FBB46217A360EULL,
+    0x2102AE466EBB1148ULL, 0xF8549E1A3AA5E00DULL, 0x07A69AFDCC42261AULL,
+    0xC4C118BFE78FEAAEULL, 0xF9F4892ED96BD438ULL, 0x1AF3DBE25D8F45DAULL,
+    0xF5B4B0B0D2DEEEB4ULL, 0x962ACEEFA82E1C84ULL, 0x046E3ECAAF453CE9ULL,
+    0xF05D129681949A4CULL, 0x964781CE734B3C84ULL, 0x9C2ED44081CE5FBDULL,
+    0x522E23F3925E319EULL, 0x177E00F9FC32F791ULL, 0x2BC60A63A6F3B3F2ULL,
+    0x222BBFAE61725606ULL, 0x486289DDCC3D6780ULL, 0x7DC7785B8EFDFC80ULL,
+    0x8AF38731C02BA980ULL, 0x1FAB64EA29A2DDF7ULL, 0xE4D9429322CD065AULL,
+    0x9DA058C67844F20CULL, 0x24C0E332B70019B0ULL, 0x233003B5A6CFE6ADULL,
+    0xD586BD01C5C217F6ULL, 0x5E5637885F29BC2BULL, 0x7EBA726D8C94094BULL,
+    0x0A56A5F0BFE39272ULL, 0xD79476A84EE20D06ULL, 0x9E4C1269BAA4BF37ULL,
+    0x17EFEE45B0DEE640ULL, 0x1D95B0A5FCF90BC6ULL, 0x93CBE0B699C2585DULL,
+    0x65FA4F227A2B6D79ULL, 0xD5F9E858292504D5ULL, 0xC2B5A03F71471A6FULL,
+    0x59300222B4561E00ULL, 0xCE2F8642CA0712DCULL, 0x7CA9723FBB2E8988ULL,
+    0x2785338347F2BA08ULL, 0xC61BB3A141E50E8CULL, 0x150F361DAB9DEC26ULL,
+    0x9F6A419D382595F4ULL, 0x64A53DC924FE7AC9ULL, 0x142DE49FFF7A7C3DULL,
+    0x0C335248857FA9E7ULL, 0x0A9C32D5EAE45305ULL, 0xE6C42178C4BBB92EULL,
+    0x71F1CE2490D20B07ULL, 0xF1BCC3D275AFE51AULL, 0xE728E8C83C334074ULL,
+    0x96FBF83A12884624ULL, 0x81A1549FD6573DA5ULL, 0x5FA7867CAF35E149ULL,
+    0x56986E2EF3ED091BULL, 0x917F1DD5F8886C61ULL, 0xD20D8C88C8FFE65FULL,
+    0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL,
+    0x1EF6E6DBB1961EC9ULL, 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL,
+    0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 0xCF3145DE0ADD4289ULL,
+    0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL,
+    0xF8D626AAAF278509ULL
+  };
+
+
+  /// Indices to the Random64[] array
+  
+  const int RandomPiece = 0;
+  const int RandomCastle = 768;
+  const int RandomEnPassant = 772;
+  const int RandomTurn = 780;
+
+  
+  /// Convert pieces to the range 0..1
+  
+  const int PieceTo12[] = {
+    0, 0, 2, 4, 6, 8, 10, 0, 0, 1, 3, 5, 7, 9, 11
+  };
+
+
+  /// Prototypes
+  
+  uint64_t book_key(const Position &pos);
+  uint64_t book_piece_key(Piece p, Square s);
+  uint64_t book_castle_key(const Position &pos);
+  uint64_t book_ep_key(const Position &pos);
+  uint64_t book_color_key(const Position &pos);
+
+  uint64_t read_integer(FILE *file, int size);
+
+}
+
+
+////
+//// Functions
+////
+
+
+/// Constructor
+
+Book::Book() {
+  bookFile = NULL;
+  bookSize = 0;
+}
+
+
+/// Book::open() opens a book file with a given file name.
+
+void Book::open(const std::string &fName) {
+  fileName = fName;
+  bookFile = fopen(fileName.c_str(), "rb");
+  if(bookFile != NULL) {
+    if(fseek(bookFile, 0, SEEK_END) == -1) {
+      std::cerr << "Failed to open book file " << fileName << std::endl;
+      exit(EXIT_FAILURE);
+    }
+    bookSize = ftell(bookFile) / 16;
+    if(bookSize == -1) {
+      std::cerr << "Failed to open book file " << fileName << std::endl;
+      exit(EXIT_FAILURE);
+    }
+  }
+}
+
+
+/// Book::close() closes the currently open book file.
+
+void Book::close() {
+  if(bookFile != NULL && fclose(bookFile) == EOF) {
+    std::cerr << "Failed to close book file" << std::endl;
+    exit(EXIT_FAILURE);
+  }
+}
+
+
+/// Book::is_open() tests whether a book file has been opened.
+
+bool Book::is_open() const {
+  return bookFile != NULL && bookSize != 0;
+}
+
+
+/// Book::file_name() returns the file name of the currently active book,
+/// or the empty string if no book is open.
+
+const std::string Book::file_name() const {
+  return this->is_open()? fileName : "";
+}
+  
+
+/// Book::get_move() gets a book move for a given position.  Returns
+/// MOVE_NONE if no book move is found.
+
+Move Book::get_move(const Position &pos) const {
+  if(this->is_open()) {
+    int bestMove = 0, bestScore = 0, move, score;
+    uint64_t key = book_key(pos);
+    BookEntry entry;
+
+    for(int i = this->find_key(key); i < bookSize; i++) {
+      this->read_entry(entry, i);
+      if(entry.key != key)
+        break;
+      move = entry.move;
+      score = entry.count;
+      assert(score > 0);
+
+      bestScore += score;
+      if(int(genrand_int32() % bestScore) < score)
+        bestMove = move;
+    }
+
+    if(bestMove != 0) {
+      MoveStack moves[256];
+      int n, j;
+      n = generate_legal_moves(pos, moves);
+      for(j = 0; j < n; j++)
+        if((int(moves[j].move) & 07777) == bestMove)
+          return moves[j].move;
+    }
+  }
+  return MOVE_NONE;
+}
+
+
+/// Book::find_key() takes a book key as input, and does a binary search
+/// through the book file for the given key.  The index to the first book
+/// entry with the same key as the input is returned.  When the key is not
+/// found in the book file, bookSize is returned.
+
+int Book::find_key(uint64_t key) const {
+  int left, right, mid;
+  BookEntry entry;
+
+  // Binary search (finds the leftmost entry)
+  left = 0;
+  right = bookSize - 1;
+
+  assert(left <= right);
+
+  while(left < right) {
+    mid = (left + right) / 2;
+    assert(mid >= left && mid < right);
+
+    this->read_entry(entry, mid);
+
+    if(key <= entry.key)
+      right = mid;
+    else
+      left = mid + 1;
+  }
+
+  assert(left == right);
+
+  this->read_entry(entry, left);
+
+  return (entry.key == key)? left : bookSize;
+}
+
+
+/// Book::read_entry() takes a BookEntry reference and an integer index as
+/// input, and looks up the opening book entry at the given index in the book
+/// file.  The book entry is copied to the first input parameter.
+
+void Book::read_entry(BookEntry& entry, int n) const {
+  assert(n >= 0 && n < bookSize);
+  assert(bookFile != NULL);
+
+  if(fseek(bookFile, n*16, SEEK_SET) == -1) {
+    std::cerr << "Failed to read book entry at index " << n << std::endl;
+    exit(EXIT_FAILURE);
+  }
+
+  entry.key = read_integer(bookFile, 8);
+  entry.move = read_integer(bookFile, 2);
+  entry.count = read_integer(bookFile, 2);
+  entry.n = read_integer(bookFile, 2);
+  entry.sum = read_integer(bookFile, 2);
+}
+
+
+////
+//// Local definitions
+////
+
+namespace {
+
+  uint64_t book_key(const Position &pos) {
+    uint64_t result = 0ULL;
+
+    for(Color c = WHITE; c <= BLACK; c++) {
+      Bitboard b = pos.pieces_of_color(c);
+      Square s;
+      Piece p;
+      while(b != EmptyBoardBB) {
+        s = pop_1st_bit(&b);
+        p = pos.piece_on(s);
+        assert(piece_is_ok(p));
+        assert(color_of_piece(p) == c);
+
+        result ^= book_piece_key(p, s);
+      }
+    }
+
+    result ^= book_castle_key(pos);
+    result ^= book_ep_key(pos);
+    result ^= book_color_key(pos);
+
+    return result;
+  }
+        
+
+  uint64_t book_piece_key(Piece p, Square s) {
+    return Random64[RandomPiece + (PieceTo12[int(p)]^1)*64 + int(s)];
+  }
+
+
+  uint64_t book_castle_key(const Position &pos) {
+    uint64_t result = 0ULL;
+
+    if(pos.can_castle_kingside(WHITE))
+      result ^= Random64[RandomCastle+0];
+    if(pos.can_castle_queenside(WHITE))
+      result ^= Random64[RandomCastle+1];
+    if(pos.can_castle_kingside(BLACK))
+      result ^= Random64[RandomCastle+2];
+    if(pos.can_castle_queenside(BLACK))
+      result ^= Random64[RandomCastle+3];
+    return result;
+  }
+
+  
+  uint64_t book_ep_key(const Position &pos) {
+    return (pos.ep_square() == SQ_NONE)?
+      0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())];
+  }
+
+  
+  uint64_t book_color_key(const Position &pos) {
+    return (pos.side_to_move() == WHITE)? Random64[RandomTurn] : 0ULL;
+  }
+  
+
+  uint64_t read_integer(FILE *file, int size) {
+    uint64_t n = 0ULL;;
+    int i;
+    int b;
+
+    assert(file != NULL);
+    assert(size > 0 && size <= 8);
+
+    for(i = 0; i < size; i++) {
+      b = fgetc(file);
+      if(b == EOF) {
+        std::cerr << "Failed to read " << size << " bytes from book file"
+                  << std::endl;
+        exit(EXIT_FAILURE);
+      }
+      assert(b >= 0 && b < 256);
+      n = (n << 8) | b;
+    }
+    return n;
+  }
+
+}
diff --git a/src/book.h b/src/book.h
new file mode 100644 (file)
index 0000000..ee3f5c5
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung 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/>.
+*/
+
+
+/*
+  The code in this file is based on the opening book code in PolyGlot
+  by Fabien Letouzey.  PolyGlot is available under the GNU General
+  Public License, and can be downloaded from http://wbec-ridderkerk.nl
+*/
+
+
+#if !defined(BOOK_H_INCLUDED)
+#define BOOK_H_INCLUDED
+
+
+////
+//// Includes
+////
+
+#include <string>
+
+#include "move.h"
+#include "position.h"
+
+
+////
+//// Types
+////
+
+struct BookEntry {
+  uint64_t key;
+  uint16_t move;
+  uint16_t count;
+  uint16_t n;
+  uint16_t sum;
+};
+
+class Book {
+
+public:
+  // Constructors
+  Book();
+
+  // Open and close book files
+  void open(const std::string &fName);
+  void close();
+
+  // Testing if a book is opened
+  bool is_open() const;
+
+  // The file name of the currently active book
+  const std::string file_name() const;
+
+  // Get a book move for a given position
+  Move get_move(const Position &pos) const;
+
+private:
+  int find_key(uint64_t key) const;
+  void read_entry(BookEntry &entry, int n) const;
+
+  std::string fileName;
+  FILE *bookFile;
+  int bookSize;
+};
+
+
+////
+//// Global variables
+////
+
+extern Book OpeningBook;
+
+
+#endif // !defined(BOOK_H_INCLUDED)
diff --git a/src/color.cpp b/src/color.cpp
new file mode 100644 (file)
index 0000000..50965a0
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include "color.h"
+
+
+////
+//// Functions
+////
+
+/// color_is_ok(), for debugging:
+
+bool color_is_ok(Color c) {
+  return c == WHITE || c == BLACK;
+}
diff --git a/src/color.h b/src/color.h
new file mode 100644 (file)
index 0000000..37ba795
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(COLOR_H_INCLUDED)
+#define COLOR_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "misc.h"
+
+
+////
+//// Types
+////
+
+enum Color {
+  WHITE, 
+  BLACK, 
+  COLOR_NONE
+};
+
+
+////
+//// Inline functions
+////
+
+inline Color operator+ (Color c, int i) { return Color(int(c) + i); }
+inline void operator++ (Color &c, int i) { c = Color(int(c) + 1); }
+
+inline Color opposite_color(Color c) {
+  return Color(int(c) ^ 1);
+}
+
+
+////
+//// Prototypes
+////
+
+extern bool color_is_ok(Color c);
+
+
+#endif // !defined(COLOR_H_INCLUDED)
diff --git a/src/depth.h b/src/depth.h
new file mode 100644 (file)
index 0000000..493ecc4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(DEPTH_H_INCLUDED)
+#define DEPTH_H_INCLUDED
+
+////
+//// Types
+////
+
+enum Depth {
+  DEPTH_ZERO = 0,
+  DEPTH_MAX = 200  // 100 * OnePly;
+};
+
+
+////
+//// Constants
+////
+
+/// Note: If OnePly is changed, the constant HistoryMax in history.h should
+/// probably also be changed.
+
+const Depth OnePly = Depth(2);
+
+
+////
+//// Inline functions
+////
+
+inline Depth operator+ (Depth d, int i) { return Depth(int(d) + i); }
+inline Depth operator+ (Depth d1, Depth d2) { return Depth(int(d1) + int(d2)); }
+inline void operator+= (Depth &d, int i) { d = Depth(int(d) + i); }
+inline void operator+= (Depth &d1, Depth d2) { d1 += int(d2); }
+inline Depth operator- (Depth d, int i) { return Depth(int(d) - i); }
+inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); }
+inline void operator-= (Depth & d, int i) { d = Depth(int(d) - i); }
+inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); }
+inline Depth operator* (int i, Depth d) { return Depth(int(d) * i); }
+inline void operator*= (Depth &d, int i) { d = Depth(int(d) * i); }
+inline Depth operator/ (Depth d, int i) { return Depth(int(d) / i); }
+inline void operator/= (Depth &d, int i) { d = Depth(int(d) / i); }
+
+
+#endif // !defined(DEPTH_H_INCLUDED)
diff --git a/src/direction.cpp b/src/direction.cpp
new file mode 100644 (file)
index 0000000..45fda4f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include "direction.h"
+#include "square.h"
+
+
+////
+//// Variables
+////
+
+uint8_t DirectionTable[64][64];
+uint8_t SignedDirectionTable[64][64];
+
+
+////
+//// Functions
+////
+
+void init_direction_table() {
+  SquareDelta deltas[8] = {
+    DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
+  };
+  for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
+    for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
+      DirectionTable[s1][s2] = uint8_t(DIR_NONE);
+      SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
+      if(s1 == s2) continue;
+      for(SignedDirection d = SIGNED_DIR_E; d <= SIGNED_DIR_SE; d++) {
+        SquareDelta delta = deltas[d];
+        Square s3, s4;
+        for(s4 = s1 + delta, s3 = s1;
+            square_distance(s4, s3) == 1 && s4 != s2 && square_is_ok(s4);
+            s3 = s4, s4 += delta);
+        if(s4 == s2 && square_distance(s4, s3) == 1) {
+          SignedDirectionTable[s1][s2] = uint8_t(d);
+          DirectionTable[s1][s2] = uint8_t(d/2);
+          break;
+        }
+      }
+    }
+}
diff --git a/src/direction.h b/src/direction.h
new file mode 100644 (file)
index 0000000..63c7c73
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(DIRECTION_H_INCLUDED)
+#define DIRECTION_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "square.h"
+#include "types.h"
+
+
+////
+//// Types
+////
+
+enum Direction {
+  DIR_E = 0, DIR_N = 1, DIR_NE = 2, DIR_NW = 3, DIR_NONE = 4
+};
+
+enum SignedDirection {
+  SIGNED_DIR_E = 0, SIGNED_DIR_W = 1,
+  SIGNED_DIR_N = 2, SIGNED_DIR_S = 3,
+  SIGNED_DIR_NE = 4, SIGNED_DIR_SW = 5,
+  SIGNED_DIR_NW = 6, SIGNED_DIR_SE = 7,
+  SIGNED_DIR_NONE = 8
+};
+
+
+////
+//// Variables
+////
+
+extern uint8_t DirectionTable[64][64];
+extern uint8_t SignedDirectionTable[64][64];
+
+
+////
+//// Inline functions
+////
+
+inline void operator++ (Direction &d, int) { d = Direction(int(d) + 1); }
+
+inline void operator++ (SignedDirection &d, int) {
+  d = SignedDirection(int(d) + 1);
+}
+
+inline Direction direction_between_squares(Square s1, Square s2) {
+  return Direction(DirectionTable[s1][s2]);
+}
+
+inline SignedDirection signed_direction_between_squares(Square s1, Square s2) {
+  return SignedDirection(SignedDirectionTable[s1][s2]);
+}
+
+
+////
+//// Prototypes
+////
+
+extern void init_direction_table();
+
+
+#endif // !defined(DIRECTION_H_INCLUDED)
diff --git a/src/endgame.cpp b/src/endgame.cpp
new file mode 100644 (file)
index 0000000..c320ba3
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+
+#include "bitbase.h"
+#include "endgame.h"
+
+
+////
+//// Constants and variables
+////
+
+/// Evaluation functions
+
+// Generic "mate lone king" eval:
+KXKEvaluationFunction EvaluateKXK = KXKEvaluationFunction(WHITE);
+KXKEvaluationFunction EvaluateKKX = KXKEvaluationFunction(BLACK);
+
+// KBN vs K:
+KBNKEvaluationFunction EvaluateKBNK = KBNKEvaluationFunction(WHITE);
+KBNKEvaluationFunction EvaluateKKBN = KBNKEvaluationFunction(BLACK);
+
+// KP vs K:
+KPKEvaluationFunction EvaluateKPK = KPKEvaluationFunction(WHITE);
+KPKEvaluationFunction EvaluateKKP = KPKEvaluationFunction(BLACK);
+
+// KR vs KP:
+KRKPEvaluationFunction EvaluateKRKP = KRKPEvaluationFunction(WHITE);
+KRKPEvaluationFunction EvaluateKPKR = KRKPEvaluationFunction(BLACK);
+
+// KR vs KB:
+KRKBEvaluationFunction EvaluateKRKB = KRKBEvaluationFunction(WHITE);
+KRKBEvaluationFunction EvaluateKBKR = KRKBEvaluationFunction(BLACK);
+
+// KR vs KN:
+KRKNEvaluationFunction EvaluateKRKN = KRKNEvaluationFunction(WHITE);
+KRKNEvaluationFunction EvaluateKNKR = KRKNEvaluationFunction(BLACK);
+
+// KQ vs KR:
+KQKREvaluationFunction EvaluateKQKR = KQKREvaluationFunction(WHITE);
+KQKREvaluationFunction EvaluateKRKQ = KQKREvaluationFunction(BLACK);
+
+
+/// Scaling functions
+
+// KBP vs K:
+KBPKScalingFunction ScaleKBPK = KBPKScalingFunction(WHITE);
+KBPKScalingFunction ScaleKKBP = KBPKScalingFunction(BLACK);
+
+// KQ vs KRP:
+KQKRPScalingFunction ScaleKQKRP = KQKRPScalingFunction(WHITE);
+KQKRPScalingFunction ScaleKRPKQ = KQKRPScalingFunction(BLACK);
+
+// KRP vs KR:
+KRPKRScalingFunction ScaleKRPKR = KRPKRScalingFunction(WHITE);
+KRPKRScalingFunction ScaleKRKRP = KRPKRScalingFunction(BLACK);
+
+// KRPP vs KRP:
+KRPPKRPScalingFunction ScaleKRPPKRP = KRPPKRPScalingFunction(WHITE);
+KRPPKRPScalingFunction ScaleKRPKRPP = KRPPKRPScalingFunction(BLACK);
+
+// King and pawns vs king:
+KPsKScalingFunction ScaleKPsK = KPsKScalingFunction(WHITE);
+KPsKScalingFunction ScaleKKPs = KPsKScalingFunction(BLACK);
+
+// KBP vs KB:
+KBPKBScalingFunction ScaleKBPKB = KBPKBScalingFunction(WHITE);
+KBPKBScalingFunction ScaleKBKBP = KBPKBScalingFunction(BLACK);
+
+// KBP vs KN:
+KBPKNScalingFunction ScaleKBPKN = KBPKNScalingFunction(WHITE);
+KBPKNScalingFunction ScaleKNKBP = KBPKNScalingFunction(BLACK);
+
+// KNP vs K:
+KNPKScalingFunction ScaleKNPK = KNPKScalingFunction(WHITE);
+KNPKScalingFunction ScaleKKNP = KNPKScalingFunction(BLACK);
+
+// KPKP
+KPKPScalingFunction ScaleKPKPw = KPKPScalingFunction(WHITE);
+KPKPScalingFunction ScaleKPKPb = KPKPScalingFunction(BLACK);
+
+
+////
+//// Local definitions
+////
+
+namespace {
+
+  // Table used to drive the defending king towards the edge of the board
+  // in KX vs K and KQ vs KR endgames:
+  const uint8_t MateTable[64] = {
+    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 defending king towards a corner square of the
+  // right color in KBN vs K endgames:
+  const uint8_t KBNKMateTable[64] = {
+    200, 190, 180, 170, 160, 150, 140, 130,
+    190, 180, 170, 160, 150, 140, 130, 140,
+    180, 170, 155, 140, 140, 125, 140, 150,
+    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
+  };
+
+  // The attacking side is given a descending bonus based on distance between
+  // the two kings in basic endgames:
+  const int DistanceBonus[8] = {0, 0, 100, 80, 60, 40, 20, 10};
+
+  // Bitbase for KP vs K:
+  uint8_t KPKBitbase[24576];
+
+  // Penalty for big distance between king and knight for the defending king
+  // and knight in KR vs KN endgames:
+  const int KRKNKingKnightDistancePenalty[8] = { 0, 0, 4, 10, 20, 32, 48, 70 };
+
+  // Various inline functions for accessing the above arrays:
+  
+  inline Value mate_table(Square s) {
+    return Value(MateTable[s]);
+  }
+
+  inline Value kbnk_mate_table(Square s) {
+    return Value(KBNKMateTable[s]);
+  }
+
+  inline Value distance_bonus(int d) {
+    return Value(DistanceBonus[d]);
+  }
+
+  inline Value krkn_king_knight_distance_penalty(int d) {
+    return Value(KRKNKingKnightDistancePenalty[d]);
+  }
+
+  // Function for probing the KP vs K bitbase:
+  int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm);
+
+}
+    
+
+////
+//// Functions
+////
+
+/// Constructors
+
+EndgameEvaluationFunction::EndgameEvaluationFunction(Color c) {
+  strongerSide = c;
+  weakerSide = opposite_color(strongerSide);
+}
+
+KXKEvaluationFunction::KXKEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+KBNKEvaluationFunction::KBNKEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+KPKEvaluationFunction::KPKEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+KRKPEvaluationFunction::KRKPEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+KRKBEvaluationFunction::KRKBEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+KRKNEvaluationFunction::KRKNEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+KQKREvaluationFunction::KQKREvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
+
+
+ScalingFunction::ScalingFunction(Color c) {
+  strongerSide = c;
+  weakerSide = opposite_color(c);
+}
+
+KBPKScalingFunction::KBPKScalingFunction(Color c) : ScalingFunction(c) { }
+KQKRPScalingFunction::KQKRPScalingFunction(Color c) : ScalingFunction(c) { }
+KRPKRScalingFunction::KRPKRScalingFunction(Color c) : ScalingFunction(c) { }
+KRPPKRPScalingFunction::KRPPKRPScalingFunction(Color c) : ScalingFunction(c) { }
+KPsKScalingFunction::KPsKScalingFunction(Color c) : ScalingFunction(c) { }
+KBPKBScalingFunction::KBPKBScalingFunction(Color c) : ScalingFunction(c) { }
+KBPKNScalingFunction::KBPKNScalingFunction(Color c) : ScalingFunction(c) { }
+KNPKScalingFunction::KNPKScalingFunction(Color c) : ScalingFunction(c) { }
+KPKPScalingFunction::KPKPScalingFunction(Color c) : ScalingFunction(c) { }
+
+
+/// 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.
+
+Value KXKEvaluationFunction::apply(const Position &pos) {
+
+  assert(pos.non_pawn_material(weakerSide) == Value(0));
+  assert(pos.pawn_count(weakerSide) == Value(0));
+
+  Square winnerKSq = pos.king_square(strongerSide);
+  Square loserKSq = pos.king_square(weakerSide);
+
+  Value result =
+    pos.non_pawn_material(strongerSide) +
+    pos.pawn_count(strongerSide) * PawnValueEndgame +
+    mate_table(loserKSq) +
+    distance_bonus(square_distance(winnerKSq, loserKSq));
+
+  if(pos.queen_count(strongerSide) > 0 || pos.rook_count(strongerSide) > 0 ||
+     pos.bishop_count(strongerSide) > 1)
+    // TODO: check for two equal-colored bishops!
+    result += VALUE_KNOWN_WIN;
+
+  return (strongerSide == pos.side_to_move())? result : -result;
+}
+
+
+/// Mate with KBN vs K.  This is similar to KX vs K, but we have to drive the
+/// defending king towards a corner square of the right color.
+                  
+Value KBNKEvaluationFunction::apply(const Position &pos) {
+
+  assert(pos.non_pawn_material(weakerSide) == Value(0));
+  assert(pos.pawn_count(weakerSide) == Value(0));
+  assert(pos.non_pawn_material(strongerSide) ==
+         KnightValueMidgame + BishopValueMidgame);
+  assert(pos.bishop_count(strongerSide) == 1);
+  assert(pos.knight_count(strongerSide) == 1);
+  assert(pos.pawn_count(strongerSide) == 0);
+
+  Square winnerKSq = pos.king_square(strongerSide);
+  Square loserKSq = pos.king_square(weakerSide);
+  Square bishopSquare = pos.bishop_list(strongerSide, 0);
+
+  if(square_color(bishopSquare) == BLACK) {
+    winnerKSq = flop_square(winnerKSq);
+    loserKSq = flop_square(loserKSq);
+  }
+
+  Value result =
+    VALUE_KNOWN_WIN + distance_bonus(square_distance(winnerKSq, loserKSq)) +
+    kbnk_mate_table(loserKSq);
+
+  return (strongerSide == pos.side_to_move())? result : -result;
+}
+
+
+/// KP vs K.  This endgame is evaluated with the help of a bitbase.
+
+Value KPKEvaluationFunction::apply(const Position &pos) {
+
+  assert(pos.non_pawn_material(strongerSide) == Value(0));
+  assert(pos.non_pawn_material(weakerSide) == Value(0));
+  assert(pos.pawn_count(strongerSide) == 1);
+  assert(pos.pawn_count(weakerSide) == 0);
+  
+  Square wksq, bksq, wpsq;
+  Color stm;
+
+  if(strongerSide == WHITE) {
+    wksq = pos.king_square(WHITE);
+    bksq = pos.king_square(BLACK);
+    wpsq = pos.pawn_list(WHITE, 0);
+    stm = pos.side_to_move();
+  }
+  else {
+    wksq = flip_square(pos.king_square(BLACK));
+    bksq = flip_square(pos.king_square(WHITE));
+    wpsq = flip_square(pos.pawn_list(BLACK, 0));
+    stm = opposite_color(pos.side_to_move());
+  }
+
+  if(square_file(wpsq) >= FILE_E) {
+    wksq = flop_square(wksq);
+    bksq = flop_square(bksq);
+    wpsq = flop_square(wpsq);
+  }
+
+  if(probe_kpk(wksq, wpsq, bksq, stm)) {
+    Value result =
+      VALUE_KNOWN_WIN + PawnValueEndgame + Value(square_rank(wpsq));
+    return (strongerSide == pos.side_to_move())? result : -result;
+  }
+
+  return VALUE_DRAW;
+}
+
+
+/// 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.
+
+Value KRKPEvaluationFunction::apply(const Position &pos) {
+
+  assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
+  assert(pos.pawn_count(strongerSide) == 0);
+  assert(pos.non_pawn_material(weakerSide) == 0);
+  assert(pos.pawn_count(weakerSide) == 1);
+
+  Square wksq, wrsq, bksq, bpsq;
+  int tempo = (pos.side_to_move() == strongerSide);
+
+  wksq = pos.king_square(strongerSide);
+  wrsq = pos.rook_list(strongerSide, 0);
+  bksq = pos.king_square(weakerSide);
+  bpsq = pos.pawn_list(weakerSide, 0);
+
+  if(strongerSide == BLACK) {
+    wksq = flip_square(wksq);
+    wrsq = flip_square(wrsq);
+    bksq = flip_square(bksq);
+    bpsq = flip_square(bpsq);
+  }
+
+  Square queeningSq = make_square(square_file(bpsq), RANK_1);
+  Value result;
+
+  // If the stronger side's king is in front of the pawn, it's a win:
+  if(wksq < bpsq && square_file(wksq) == square_file(bpsq))
+    result = RookValueEndgame - Value(square_distance(wksq, bpsq));
+
+  // If the weaker side's king is too far from the pawn and the rook,
+  // it's a win:
+  else if(square_distance(bksq, bpsq) - (tempo^1) >= 3 &&
+          square_distance(bksq, wrsq) >= 3)
+    result = RookValueEndgame - Value(square_distance(wksq, bpsq));
+
+  // If the pawn is far advanced and supported by the defending king,
+  // the position is drawish:
+  else if(square_rank(bksq) <= RANK_3 && square_distance(bksq, bpsq) == 1 &&
+          square_rank(wksq) >= RANK_4 &&
+          square_distance(wksq, bpsq) - tempo > 2)
+    result = Value(80 - square_distance(wksq, bpsq) * 8);
+
+  else
+    result = Value(200)
+      - Value(square_distance(wksq, bpsq + DELTA_S) * 8)
+      + Value(square_distance(bksq, bpsq + DELTA_S) * 8)
+      + Value(square_distance(bpsq, queeningSq) * 8);
+
+  return (strongerSide == pos.side_to_move())? result : -result;
+}
+
+
+/// KR vs KB.  This is very simple, and always returns drawish scores.  The
+/// score is slightly bigger when the defending king is close to the edge.
+
+Value KRKBEvaluationFunction::apply(const Position &pos) {
+
+  assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
+  assert(pos.pawn_count(strongerSide) == 0);
+  assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame);
+  assert(pos.pawn_count(weakerSide) == 0);
+  assert(pos.bishop_count(weakerSide) == 1);
+
+  Value result = mate_table(pos.king_square(weakerSide));
+  return (pos.side_to_move() == strongerSide)? 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.
+
+Value KRKNEvaluationFunction::apply(const Position &pos) {
+
+  assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
+  assert(pos.pawn_count(strongerSide) == 0);
+  assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame);
+  assert(pos.pawn_count(weakerSide) == 0);
+  assert(pos.knight_count(weakerSide) == 1);
+
+  Square defendingKSq = pos.king_square(weakerSide);
+  Square nSq = pos.knight_list(weakerSide, 0);
+
+  Value result = Value(10) + mate_table(defendingKSq) +
+    krkn_king_knight_distance_penalty(square_distance(defendingKSq, nSq));
+
+  return (strongerSide == 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 be
+/// able to win KQ vs KR.
+
+Value KQKREvaluationFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
+  assert(pos.pawn_count(strongerSide) == 0);
+  assert(pos.non_pawn_material(weakerSide) == RookValueMidgame);
+  assert(pos.pawn_count(weakerSide) == 0);
+
+  Square winnerKSq = pos.king_square(strongerSide);
+  Square loserKSq = pos.king_square(weakerSide);
+  
+  Value result = QueenValueEndgame - RookValueEndgame +
+    mate_table(loserKSq) + distance_bonus(square_distance(winnerKSq, loserKSq));
+
+  return (strongerSide == pos.side_to_move())? result : -result;
+}
+
+
+/// KBPKScalingFunction scales endgames where the stronger side has king,
+/// bishop and one or more pawns.  It checks for draws with rook pawns and a
+/// bishop of the wrong color.  If such a draw is detected, ScaleFactor(0) is
+/// returned.  If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
+/// will be used.
+
+ScaleFactor KBPKScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
+  assert(pos.bishop_count(strongerSide) == 1);
+  assert(pos.pawn_count(strongerSide) >= 1);
+
+  // No assertions about the material of weakerSide, because we want draws to
+  // be detected even when the weaker side has some pawns.
+
+  Bitboard pawns = pos.pawns(strongerSide);
+  File pawnFile = square_file(pos.pawn_list(strongerSide, 0));
+
+  if((pawnFile == FILE_A || pawnFile == FILE_H) &&
+     (pawns & ~file_bb(pawnFile)) == EmptyBoardBB) {
+    // All pawns are on a single rook file.
+
+    Square bishopSq = pos.bishop_list(strongerSide, 0);
+    Square queeningSq =
+      relative_square(strongerSide, make_square(pawnFile, RANK_8));
+    Square kingSq = pos.king_square(weakerSide);
+
+    if(square_color(queeningSq) != square_color(bishopSq) &&
+       file_distance(square_file(kingSq), pawnFile) <= 1) {
+      // The bishop has the wrong color, and the defending king is on the
+      // file of the pawn(s) or the neighboring file.  Find the rank of the
+      // frontmost pawn:
+
+      Rank rank;
+      if(strongerSide == WHITE) {
+        for(rank = RANK_7; (rank_bb(rank) & pawns) == EmptyBoardBB; rank--);
+        assert(rank >= RANK_2 && rank <= RANK_7);
+      }
+      else {
+        for(rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++);
+        rank = Rank(rank^7);  // HACK
+        assert(rank >= RANK_2 && rank <= RANK_7);
+      }
+      // If the defending king has distance 1 to the promotion square or
+      // is placed somewhere in front of the pawn, it's a draw.
+      if(square_distance(kingSq, queeningSq) <= 1 ||
+         pawn_rank(strongerSide, kingSq) >= rank)
+        return ScaleFactor(0);
+    }
+  }
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KQKRPScalingFunction scales endgames where the stronger side has only
+/// king and queen, while the weaker side has at least a rook and a pawn.
+/// It tests for fortress draws with a rook on the third rank defended by
+/// a pawn.
+
+ScaleFactor KQKRPScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
+  assert(pos.queen_count(strongerSide) == 1);
+  assert(pos.pawn_count(strongerSide) == 0);
+  assert(pos.rook_count(weakerSide) == 1);
+  assert(pos.pawn_count(weakerSide) >= 1);
+
+  Square kingSq = pos.king_square(weakerSide);
+  if(pawn_rank(weakerSide, kingSq) <= RANK_2 &&
+     pawn_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 &&
+     (pos.rooks(weakerSide) & relative_rank_bb(weakerSide, RANK_3)) &&
+     (pos.pawns(weakerSide) & relative_rank_bb(weakerSide, RANK_2)) &&
+     (pos.king_attacks(kingSq) & pos.pawns(weakerSide))) {
+    Square rsq = pos.rook_list(weakerSide, 0);
+    if(pos.pawn_attacks(strongerSide, rsq) & pos.pawns(weakerSide))
+      return ScaleFactor(0);
+  }
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KRPKRScalingFunction scales KRP vs KR endgames.  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 not very pretty.
+
+ScaleFactor KRPKRScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
+  assert(pos.pawn_count(strongerSide) == 1);
+  assert(pos.non_pawn_material(weakerSide) == RookValueMidgame);
+  assert(pos.pawn_count(weakerSide) == 0);
+
+  Square wksq = pos.king_square(strongerSide);
+  Square wrsq = pos.rook_list(strongerSide, 0);
+  Square wpsq = pos.pawn_list(strongerSide, 0);
+  Square bksq = pos.king_square(weakerSide);
+  Square brsq = pos.rook_list(weakerSide, 0);
+
+  // Orient the board in such a way that the stronger side is white, and the
+  // pawn is on the left half of the board:
+  if(strongerSide == BLACK) {
+    wksq = flip_square(wksq);
+    wrsq = flip_square(wrsq);
+    wpsq = flip_square(wpsq);
+    bksq = flip_square(bksq);
+    brsq = flip_square(brsq);
+  }
+  if(square_file(wpsq) > FILE_D) {
+    wksq = flop_square(wksq);
+    wrsq = flop_square(wrsq);
+    wpsq = flop_square(wpsq);
+    bksq = flop_square(bksq);
+    brsq = flop_square(brsq);
+  }
+
+  File f = square_file(wpsq);
+  Rank r = square_rank(wpsq);
+  Square queeningSq = make_square(f, RANK_8);
+  int tempo = (pos.side_to_move() == strongerSide);
+
+  // 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 &&
+     (square_rank(brsq) == RANK_6 || (r <= RANK_3 &&
+                                      square_rank(wrsq) != RANK_6)))
+    return ScaleFactor(0);
+
+  // 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 &&
+     square_rank(wksq) + tempo <= RANK_6 &&
+     (square_rank(brsq) == RANK_1 ||
+      (!tempo && abs(square_file(brsq) - f) >= 3)))
+    return ScaleFactor(0);
+
+  if(r >= RANK_6 && bksq == queeningSq && square_rank(brsq) == RANK_1 &&
+     (!tempo || square_distance(wksq, wpsq) >= 2))
+    return ScaleFactor(0);
+
+  // 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) &&
+     square_file(brsq) == FILE_A &&
+     (square_rank(brsq) <= RANK_3 || square_file(wksq) >= FILE_D ||
+      square_rank(wksq) <= RANK_5))
+    return ScaleFactor(0);
+
+  // 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 ScaleFactor(0);
+
+  // 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 && square_file(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 && square_file(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)));
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KRPPKRPScalingFunction scales KRPP vs KRP endgames.  There is only a
+/// single pattern:  If the stronger side has no pawns and the defending king
+/// is actively placed, the position is drawish.
+
+ScaleFactor KRPPKRPScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
+  assert(pos.pawn_count(strongerSide) == 2);
+  assert(pos.non_pawn_material(weakerSide) == RookValueMidgame);
+  assert(pos.pawn_count(weakerSide) == 1);
+
+  Square wpsq1 = pos.pawn_list(strongerSide, 0);
+  Square wpsq2 = pos.pawn_list(strongerSide, 1);
+  Square bksq = pos.king_square(weakerSide);
+
+  // Does the stronger side have a passed pawn?
+  if(pos.pawn_is_passed(strongerSide, wpsq1) ||
+     pos.pawn_is_passed(strongerSide, wpsq2))
+    return SCALE_FACTOR_NONE;
+
+  Rank r = Max(pawn_rank(strongerSide, wpsq1), pawn_rank(strongerSide, wpsq2));
+
+  if(file_distance(bksq, wpsq1) <= 1 && file_distance(bksq, wpsq2) <= 1
+     && pawn_rank(strongerSide, 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;
+}
+
+
+/// KPsKScalingFunction scales endgames with king and two or more pawns
+/// against king.  There is just a single rule here:  If all pawns are on
+/// the same rook file and are blocked by the defending king, it's a draw.
+
+ScaleFactor KPsKScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == Value(0));
+  assert(pos.pawn_count(strongerSide) >= 2);
+  assert(pos.non_pawn_material(weakerSide) == Value(0));
+  assert(pos.pawn_count(weakerSide) == 0);
+
+  Bitboard pawns = pos.pawns(strongerSide);
+
+  // Are all pawns on the 'a' file?
+  if((pawns & ~FileABB) == EmptyBoardBB) {
+    // Does the defending king block the pawns?
+    Square ksq = pos.king_square(weakerSide);
+    if(square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1)
+      return ScaleFactor(0);
+    else if(square_file(ksq) == FILE_A &&
+       (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
+      return ScaleFactor(0);
+    else
+      return SCALE_FACTOR_NONE;
+  }
+  // Are all pawns on the 'h' file?
+  else if((pawns & ~FileHBB) == EmptyBoardBB) {
+    // Does the defending king block the pawns?
+    Square ksq = pos.king_square(weakerSide);
+    if(square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1)
+      return ScaleFactor(0);
+    else if(square_file(ksq) == FILE_H &&
+       (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
+      return ScaleFactor(0);
+    else
+      return SCALE_FACTOR_NONE;
+  }
+  else
+    return SCALE_FACTOR_NONE;
+}
+
+
+/// KBPKBScalingFunction scales KBP vs KB endgames.  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.
+
+ScaleFactor KBPKBScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
+  assert(pos.bishop_count(strongerSide) == 1);
+  assert(pos.pawn_count(strongerSide) == 1);
+  assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame);
+  assert(pos.bishop_count(weakerSide) == 1);
+  assert(pos.pawn_count(weakerSide) == 0);
+
+  Square pawnSq = pos.pawn_list(strongerSide, 0);
+  Square strongerBishopSq = pos.bishop_list(strongerSide, 0);
+  Square weakerBishopSq = pos.bishop_list(weakerSide, 0);
+  Square weakerKingSq = pos.king_square(weakerSide);
+
+  // Case 1: Defending king blocks the pawn, and cannot be driven away.
+  if(square_file(weakerKingSq) == square_file(pawnSq)
+     && pawn_rank(strongerSide, pawnSq) < pawn_rank(strongerSide, weakerKingSq)
+     && (square_color(weakerKingSq) != square_color(strongerBishopSq)
+         || pawn_rank(strongerSide, weakerKingSq) <= RANK_6))
+    return ScaleFactor(0);
+
+  // Case 2: Opposite colored bishops.
+  if(square_color(strongerBishopSq) != square_color(weakerBishopSq)) {
+    
+    // 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(pawn_rank(strongerSide, pawnSq) <= RANK_5)
+      return ScaleFactor(0);
+    else {
+      Bitboard ray =
+        ray_bb(pawnSq, (strongerSide == WHITE)? SIGNED_DIR_N : SIGNED_DIR_S);
+      if(ray & pos.kings(weakerSide))
+        return ScaleFactor(0);
+      if((pos.bishop_attacks(weakerBishopSq) & ray)
+         && square_distance(weakerBishopSq, pawnSq) >= 3)
+        return ScaleFactor(0);
+    }
+  }
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KBPKNScalingFunction scales KBP vs KN endgames.  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.
+
+ScaleFactor KBPKNScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
+  assert(pos.bishop_count(strongerSide) == 1);
+  assert(pos.pawn_count(strongerSide) == 1);
+  assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame);
+  assert(pos.knight_count(weakerSide) == 1);
+  assert(pos.pawn_count(weakerSide) == 0);
+
+  Square pawnSq = pos.pawn_list(strongerSide, 0);
+  Square strongerBishopSq = pos.bishop_list(strongerSide, 0);
+  Square weakerKingSq = pos.king_square(weakerSide);
+      
+  if(square_file(weakerKingSq) == square_file(pawnSq)
+     && pawn_rank(strongerSide, pawnSq) < pawn_rank(strongerSide, weakerKingSq)
+     && (square_color(weakerKingSq) != square_color(strongerBishopSq)
+         || pawn_rank(strongerSide, weakerKingSq) <= RANK_6))
+    return ScaleFactor(0);
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KNPKScalingFunction scales KNP vs K endgames.  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.
+
+ScaleFactor KNPKScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame);
+  assert(pos.knight_count(strongerSide) == 1);
+  assert(pos.pawn_count(strongerSide) == 1);
+  assert(pos.non_pawn_material(weakerSide) == Value(0));
+  assert(pos.pawn_count(weakerSide) == 0);
+
+  Square pawnSq = pos.pawn_list(strongerSide, 0);
+  Square weakerKingSq = pos.king_square(weakerSide);
+
+  if(pawnSq == relative_square(strongerSide, SQ_A7) &&
+     square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1)
+    return ScaleFactor(0);
+
+  if(pawnSq == relative_square(strongerSide, SQ_H7) &&
+     square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1)
+    return ScaleFactor(0);
+
+  return SCALE_FACTOR_NONE;
+}
+
+
+/// KPKPScalingFunction scales KP vs KP endgames.  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, she 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).
+
+ScaleFactor KPKPScalingFunction::apply(const Position &pos) {
+  assert(pos.non_pawn_material(strongerSide) == Value(0));
+  assert(pos.non_pawn_material(weakerSide) == Value(0));
+  assert(pos.pawn_count(WHITE) == 1);
+  assert(pos.pawn_count(BLACK) == 1);
+
+  Square wksq, bksq, wpsq;
+  Color stm;
+
+  if(strongerSide == WHITE) {
+    wksq = pos.king_square(WHITE);
+    bksq = pos.king_square(BLACK);
+    wpsq = pos.pawn_list(WHITE, 0);
+    stm = pos.side_to_move();
+  }
+  else {
+    wksq = flip_square(pos.king_square(BLACK));
+    bksq = flip_square(pos.king_square(WHITE));
+    wpsq = flip_square(pos.pawn_list(BLACK, 0));
+    stm = opposite_color(pos.side_to_move());
+  }
+
+  if(square_file(wpsq) >= FILE_E) {
+    wksq = flop_square(wksq);
+    bksq = flop_square(bksq);
+    wpsq = flop_square(wpsq);
+  }
+
+  // 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(square_rank(wpsq) >= RANK_5 && square_file(wpsq) != 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.
+  if(probe_kpk(wksq, wpsq, bksq, stm))
+    return SCALE_FACTOR_NONE;
+  else
+    return ScaleFactor(0);
+}
+
+
+/// init_bitbases() is called during program initialization, and simply loads
+/// bitbases from disk into memory.  At the moment, there is only the bitbase
+/// for KP vs K, but we may decide to add other bitbases later.
+
+void init_bitbases() {
+  generate_kpk_bitbase(KPKBitbase);
+}
+
+
+namespace {
+
+  // Probe the KP vs K bitbase:
+
+  int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm) {
+    int wp = int(square_file(wpsq)) + (int(square_rank(wpsq)) - 1) * 4;
+    int index = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*wp;
+    
+    assert(index >= 0 && index < 24576*8);
+    return KPKBitbase[index/8] & (1 << (index&7));
+  }
+  
+}
diff --git a/src/endgame.h b/src/endgame.h
new file mode 100644 (file)
index 0000000..ae3526f
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(ENDGAME_H_INCLUDED)
+#define ENDGAME_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "position.h"
+#include "scale.h"
+#include "value.h"
+
+
+////
+//// Types
+////
+
+/// Abstract base class for all special endgame evaluation functions:
+
+class EndgameEvaluationFunction {
+public:
+  EndgameEvaluationFunction(Color c);
+  virtual ~EndgameEvaluationFunction() { }
+
+  virtual Value apply(const Position &pos) =0;
+
+protected:
+  Color strongerSide, weakerSide;
+};
+
+
+/// Subclasses for various concrete endgames:
+
+// Generic "mate lone king" eval:
+class KXKEvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KXKEvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+// KBN vs K:
+class KBNKEvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KBNKEvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+// KP vs K:
+class KPKEvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KPKEvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+// KR vs KP:
+class KRKPEvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KRKPEvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+// KR vs KB:
+class KRKBEvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KRKBEvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+// KR vs KN:
+class KRKNEvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KRKNEvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+// KQ vs KR:
+class KQKREvaluationFunction : public EndgameEvaluationFunction {
+public:
+  KQKREvaluationFunction(Color c);
+  Value apply(const Position &pos);
+};
+
+
+/// Abstract base class for all evaluation scaling functions:
+
+class ScalingFunction {
+public:
+  ScalingFunction(Color c);
+  virtual ~ScalingFunction() { }
+
+  virtual ScaleFactor apply(const Position &pos) =0;
+
+protected:
+  Color strongerSide, weakerSide;
+};
+
+
+/// Subclasses for various concrete endgames:
+
+// KBP vs K:
+class KBPKScalingFunction : public ScalingFunction {
+public:
+  KBPKScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KQ vs KRP:
+class KQKRPScalingFunction: public ScalingFunction {
+public:
+  KQKRPScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KRP vs KR:
+class KRPKRScalingFunction : public ScalingFunction {
+public:
+  KRPKRScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KRPP vs KRP:
+class KRPPKRPScalingFunction : public ScalingFunction {
+public:
+  KRPPKRPScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// King and pawns vs king:
+class KPsKScalingFunction : public ScalingFunction {
+public:
+  KPsKScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KBP vs KB:
+class KBPKBScalingFunction : public ScalingFunction {
+public:
+  KBPKBScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KBP vs KN:
+class KBPKNScalingFunction : public ScalingFunction {
+public:
+  KBPKNScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KNP vs K:
+class KNPKScalingFunction : public ScalingFunction {
+public:
+  KNPKScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+// KP vs KP:
+class KPKPScalingFunction : public ScalingFunction {
+public:
+  KPKPScalingFunction(Color c);
+  ScaleFactor apply(const Position &pos);
+};
+
+
+////
+//// Constants and variables
+////
+
+// Generic "mate lone king" eval:
+extern KXKEvaluationFunction EvaluateKXK, EvaluateKKX;
+
+// KBN vs K:
+extern KBNKEvaluationFunction EvaluateKBNK, EvaluateKKBN;
+
+// KP vs K:
+extern KPKEvaluationFunction EvaluateKPK, EvaluateKKP;
+
+// KR vs KP:
+extern KRKPEvaluationFunction EvaluateKRKP, EvaluateKPKR;
+
+// KR vs KB:
+extern KRKBEvaluationFunction EvaluateKRKB, EvaluateKBKR;
+
+// KR vs KN:
+extern KRKNEvaluationFunction EvaluateKRKN, EvaluateKNKR;
+
+// KQ vs KR:
+extern KQKREvaluationFunction EvaluateKQKR, EvaluateKRKQ;
+
+// KBP vs K:
+extern KBPKScalingFunction ScaleKBPK, ScaleKKBP;
+
+// KQ vs KRP:
+extern KQKRPScalingFunction ScaleKQKRP, ScaleKRPKQ;
+
+// KRP vs KR:
+extern KRPKRScalingFunction ScaleKRPKR, ScaleKRKRP;
+
+// KRPP vs KRP:
+extern KRPPKRPScalingFunction ScaleKRPPKRP, ScaleKRPKRPP;
+
+// King and pawns vs king:
+extern KPsKScalingFunction ScaleKPsK, ScaleKKPs;
+
+// KBP vs KB:
+extern KBPKBScalingFunction ScaleKBPKB, ScaleKBKBP;
+
+// KBP vs KN:
+extern KBPKNScalingFunction ScaleKBPKN, ScaleKNKBP;
+
+// KNP vs K:
+extern KNPKScalingFunction ScaleKNPK, ScaleKKNP;
+
+// KP vs KP:
+extern KPKPScalingFunction ScaleKPKPw, ScaleKPKPb;
+
+
+////
+//// Prototypes
+////
+
+extern void init_bitbases();
+
+
+#endif // !defined(ENDGAME_H_INCLUDED)
diff --git a/src/evaluate.cpp b/src/evaluate.cpp
new file mode 100644 (file)
index 0000000..48cbfc1
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+#include <cstring>
+
+#include "evaluate.h"
+#include "material.h"
+#include "pawns.h"
+#include "scale.h"
+#include "thread.h"
+#include "ucioption.h"
+
+
+////
+//// Local definitions
+////
+
+namespace {
+
+  const int Sign[2] = {1, -1};
+
+  // Evaluation grain size, must be a power of 2.
+  const int GrainSize = 4;
+
+  // Evaluation weights
+  int WeightMobilityMidgame = 0x100;
+  int WeightMobilityEndgame = 0x100;
+  int WeightPawnStructureMidgame = 0x100;
+  int WeightPawnStructureEndgame = 0x100;
+  int WeightPassedPawnsMidgame = 0x100;
+  int WeightPassedPawnsEndgame = 0x100;
+  int WeightKingSafety[2] = { 0x100, 0x100 };
+
+  // Internal evaluation weights.  These are applied on top of the evaluation
+  // weights read from UCI parameters.  The purpose is to be able to change
+  // the evaluation weights while keeping the default values of the UCI
+  // parameters at 100, which looks prettier.
+  const int WeightMobilityMidgameInternal = 0x100;
+  const int WeightMobilityEndgameInternal = 0x100;
+  const int WeightPawnStructureMidgameInternal = 0x100;
+  const int WeightPawnStructureEndgameInternal = 0x100;
+  const int WeightPassedPawnsMidgameInternal = 0x100;
+  const int WeightPassedPawnsEndgameInternal = 0x100;
+  const int WeightKingSafetyInternal = 0x100;
+
+  // Knight mobility bonus in middle game and endgame, indexed by the number
+  // of attacked squares not occupied by friendly piecess.
+  const Value MidgameKnightMobilityBonus[] = {
+    Value(-30), Value(-20), Value(-10), Value(0), Value(10),
+    Value(20), Value(25), Value(30), Value(30)
+  };
+
+  const Value EndgameKnightMobilityBonus[] = {
+    Value(-30), Value(-20), Value(-10), Value(0), Value(10),
+    Value(20), Value(25), Value(30), Value(30)
+  };
+
+  // Bishop mobility bonus in middle game and endgame, indexed by the number
+  // of attacked squares not occupied by friendly pieces.  X-ray attacks through
+  // queens are also included.
+  const Value MidgameBishopMobilityBonus[] = {
+    Value(-30), Value(-15), Value(0), Value(15), Value(30), Value(45),
+    Value(58), Value(66), Value(72), Value(76), Value(78), Value(80),
+    Value(81), Value(82), Value(83), Value(83)
+  };
+
+  const Value EndgameBishopMobilityBonus[] = {
+    Value(-30), Value(-15), Value(0), Value(15), Value(30), Value(45),
+    Value(58), Value(66), Value(72), Value(76), Value(78), Value(80),
+    Value(81), Value(82), Value(83), Value(83)
+  };
+
+  // Rook mobility bonus in middle game and endgame, indexed by the number
+  // of attacked squares not occupied by friendly pieces.  X-ray attacks through
+  // queens and rooks are also included.
+  const Value MidgameRookMobilityBonus[] = {
+    Value(-18), Value(-12), Value(-6), Value(0), Value(6), Value(12),
+    Value(16), Value(21), Value(24), Value(27), Value(28), Value(29),
+    Value(30), Value(31), Value(32), Value(33)
+  };
+  
+  const Value EndgameRookMobilityBonus[] = {
+    Value(-30), Value(-18), Value(-6), Value(6), Value(18), Value(30),
+    Value(42), Value(54), Value(66), Value(74), Value(78), Value(80),
+    Value(81), Value(82), Value(83), Value(83)
+  };
+
+  // Queen mobility bonus in middle game and endgame, indexed by the number
+  // of attacked squares not occupied by friendly pieces.
+  const Value MidgameQueenMobilityBonus[] = {
+    Value(-10), Value(-8), Value(-6), Value(-4), Value(-2), Value(0), Value(2),
+    Value(4), Value(6), Value(8), Value(10), Value(12), Value(13), Value(14),
+    Value(15), Value(16), Value(16), Value(16), Value(16), Value(16),
+    Value(16), Value(16), Value(16), Value(16), Value(16), Value(16),
+    Value(16), Value(16), Value(16), Value(16), Value(16), Value(16)
+  };
+
+  const Value EndgameQueenMobilityBonus[] = {
+    Value(-20), Value(-15), Value(-10), Value(-5), Value(0), Value(5),
+    Value(10), Value(15), Value(19), Value(23), Value(27), Value(29),
+    Value(30), Value(30), Value(30), Value(30), Value(30), Value(30),
+    Value(30), Value(30), Value(30), Value(30), Value(30), Value(30),
+    Value(30), Value(30), Value(30), Value(30), Value(30), Value(30),
+    Value(30), Value(30)
+  };
+
+
+  // Outpost bonuses for knights and bishops, indexed by square (from white's
+  // point of view).
+  const Value KnightOutpostBonus[64] = {
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),
+    Value(0),Value(0),Value(5),Value(10),Value(10),Value(5),Value(0),Value(0),
+    Value(0),Value(5),Value(20),Value(30),Value(30),Value(20),Value(5),Value(0),
+    Value(0),Value(10),Value(30),Value(40),Value(40),Value(30),Value(10),Value(0),
+    Value(0),Value(5),Value(20),Value(20),Value(20),Value(20),Value(5),Value(0),
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0)
+  };
+
+  const Value BishopOutpostBonus[64] = {
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),
+    Value(0),Value(0),Value(5),Value(5),Value(5),Value(5),Value(0),Value(0),
+    Value(0),Value(5),Value(10),Value(10),Value(10),Value(10),Value(5),Value(0),
+    Value(0),Value(10),Value(20),Value(20),Value(20),Value(20),Value(10),Value(0),
+    Value(0),Value(5),Value(8),Value(8),Value(8),Value(8),Value(5),Value(0),
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),
+    Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0),Value(0)
+  };
+
+  // Bonus for unstoppable passed pawns:
+  const Value UnstoppablePawnValue = Value(0x500);
+
+  // Rooks and queens on the 7th rank:
+  const Value MidgameRookOn7thBonus = Value(50);
+  const Value EndgameRookOn7thBonus = Value(100);
+  const Value MidgameQueenOn7thBonus = Value(25);
+  const Value EndgameQueenOn7thBonus = Value(50);
+
+  // Rooks on open files:
+  const Value RookOpenFileBonus = Value(40);
+  const Value RookHalfOpenFileBonus = Value(20);
+
+  // Penalty for rooks trapped inside a friendly king which has lost the
+  // right to castle:
+  const Value TrappedRookPenalty = Value(180);
+
+  // Penalty for a bishop on a7/h7 (a2/h2 for black) which is trapped by
+  // enemy pawns:
+  const Value TrappedBishopA7H7Penalty = Value(300);
+
+  // Bitboard masks for detecting trapped bishops on a7/h7 (a2/h2 for black):
+  const Bitboard MaskA7H7[2] = {
+    ((1ULL << SQ_A7) | (1ULL << SQ_H7)),
+    ((1ULL << SQ_A2) | (1ULL << SQ_H2))
+  };
+
+  // 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 Value TrappedBishopA1H1Penalty = Value(100);
+
+  // Bitboard masks for detecting trapped bishops on a1/h1 (a8/h8 for black):
+  const Bitboard MaskA1H1[2] = {
+    ((1ULL << SQ_A1) | (1ULL << SQ_H1)),
+    ((1ULL << SQ_A8) | (1ULL << SQ_H8))
+  };
+
+  
+  /// King safety constants and variables.  The king safety scores are taken
+  /// from the array SafetyTable[].  Various little "meta-bonuses" measuring
+  /// the strength of the attack are added up into an integer, which is used
+  /// as an index to SafetyTable[].
+
+  // Attack weights for each piece type.
+  const int QueenAttackWeight = 5;
+  const int RookAttackWeight = 3;
+  const int BishopAttackWeight = 2;
+  const int KnightAttackWeight = 2;
+
+  // Bonuses for safe checks for each piece type.  
+  int QueenContactCheckBonus = 4;
+  int RookContactCheckBonus = 2;
+  int QueenCheckBonus = 2;
+  int RookCheckBonus = 1;
+  int BishopCheckBonus = 1;
+  int KnightCheckBonus = 1;
+  int DiscoveredCheckBonus = 3;
+
+  // Scan for queen contact mates?
+  const bool QueenContactMates = true;
+
+  // Bonus for having a mate threat.
+  int MateThreatBonus = 3;
+
+  // InitKingDanger[] contains bonuses based on the position of the defending
+  // king.
+  const int InitKingDanger[64] = {
+    2, 0, 2, 5, 5, 2, 0, 2,
+    2, 2, 4, 8, 8, 4, 2, 2,
+    7, 10, 12, 12, 12, 12, 10, 7,
+    15, 15, 15, 15, 15, 15, 15, 15,
+    15, 15, 15, 15, 15, 15, 15, 15,
+    15, 15, 15, 15, 15, 15, 15, 15,
+    15, 15, 15, 15, 15, 15, 15, 15,
+  };
+
+  // SafetyTable[] contains the actual king safety scores.  It is initialized
+  // in init_safety().
+  Value SafetyTable[100];
+
+
+  // Pawn and material hash tables, indexed by the current thread id:
+  PawnInfoTable *PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+  MaterialInfoTable *MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+  // Sizes of pawn and material hash tables:
+  const int PawnTableSize = 16384;
+  const int MaterialTableSize = 1024;
+
+  // Array which gives the number of nonzero bits in an 8-bit integer:
+  uint8_t BitCount8Bit[256];
+
+  // Function prototypes:
+  void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei);
+  void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei);
+  void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei);
+  void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei);
+  void evaluate_king(const Position &p, Square s, Color us, EvalInfo &ei);
+
+  void evaluate_passed_pawns(const Position &pos, EvalInfo &ei);
+  void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
+                                    EvalInfo &ei);
+  void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us,
+                                    EvalInfo &ei);
+
+  Value apply_weight(Value v, int w);
+  Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]);
+
+  int count_1s_8bit(int b);
+
+  int compute_weight(int uciWeight, int internalWeight);
+  void init_safety();
+
+}
+
+
+////
+//// Functions
+////
+
+/// evaluate() is the main evaluation function.  It always computes two
+/// values, an endgame score and a middle game score, and interpolates
+/// between them based on the remaining material.
+
+Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
+  Color stm;
+  Square s;
+  ScaleFactor factor[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
+  Phase phase;
+
+  memset(&ei, 0, sizeof(EvalInfo));
+
+  assert(pos.is_ok());
+  assert(threadID >= 0 && threadID < THREAD_MAX);
+
+  stm = pos.side_to_move();
+
+  // Initialize by reading the incrementally updated scores included in the
+  // position object (material + piece square tables):
+  ei.mgValue = pos.mg_value();
+  ei.egValue = pos.eg_value();
+
+  // Probe the material hash table:
+  ei.mi = MaterialTable[threadID]->get_material_info(pos);
+  ei.mgValue += ei.mi->mg_value();
+  ei.egValue += ei.mi->eg_value();
+
+  factor[WHITE] = ei.mi->scale_factor(pos, WHITE);
+  factor[BLACK] = ei.mi->scale_factor(pos, BLACK);
+
+  // 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);
+
+  phase = pos.game_phase();
+
+  // Probe the pawn hash table:
+  ei.pi = PawnTable[threadID]->get_pawn_info(pos);
+  ei.mgValue += apply_weight(ei.pi->mg_value(), WeightPawnStructureMidgame);
+  ei.egValue += apply_weight(ei.pi->eg_value(), WeightPawnStructureEndgame);
+
+  // Initialize king attack bitboards and king attack zones for both sides:
+  ei.attackedBy[WHITE][KING] = pos.king_attacks(pos.king_square(WHITE));
+  ei.attackedBy[BLACK][KING] = pos.king_attacks(pos.king_square(BLACK));
+  ei.attackZone[WHITE] =
+    ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8);
+  ei.attackZone[BLACK] =
+    ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8);
+
+  // Initialize pawn attack bitboards for both sides:
+  ei.attackedBy[WHITE][PAWN] =
+    ((pos.pawns(WHITE) << 9) & ~FileABB) | ((pos.pawns(WHITE) << 7) & ~FileHBB);
+  ei.attackCount[WHITE] +=
+    count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2;
+  ei.attackedBy[BLACK][PAWN] =
+    ((pos.pawns(BLACK) >> 7) & ~FileABB) | ((pos.pawns(BLACK) >> 9) & ~FileHBB);
+  ei.attackCount[BLACK] +=
+    count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2;
+
+  // Evaluate pieces:
+  for(Color c = WHITE; c <= BLACK; c++) {
+    Bitboard b;
+
+    // Knights
+    for(int i = 0; i < pos.knight_count(c); i++) {
+      s = pos.knight_list(c, i);
+      evaluate_knight(pos, s, c, ei);
+    }
+    
+    // Bishops
+    for(int i = 0; i < pos.bishop_count(c); i++) {
+      s = pos.bishop_list(c, i);
+      evaluate_bishop(pos, s, c, ei);
+    }
+
+    // Rooks
+    for(int i = 0; i < pos.rook_count(c); i++) {
+      s = pos.rook_list(c, i);
+      evaluate_rook(pos, s, c, ei);
+    }
+
+    // Queens
+    for(int i = 0; i < pos.queen_count(c); i++) {
+      s = pos.queen_list(c, i);
+      evaluate_queen(pos, s, c, ei);
+    }
+
+    // Some special patterns:
+
+    // Trapped bishops on a7/h7/a2/h2
+    b = pos.bishops(c) & MaskA7H7[c];
+    while(b) {
+      s = pop_1st_bit(&b);
+      evaluate_trapped_bishop_a7h7(pos, s, c, ei);
+    }
+
+    // Trapped bishops on a1/h1/a8/h8 in Chess960:
+    if(Chess960) {
+      b = pos.bishops(c) & MaskA1H1[c];
+      while(b) {
+        s = pop_1st_bit(&b);
+        evaluate_trapped_bishop_a1h1(pos, s, c, ei);
+      }
+    }
+
+    ei.attackedBy[c][0] =
+      ei.attackedBy[c][PAWN] | ei.attackedBy[c][KNIGHT] 
+      | ei.attackedBy[c][BISHOP] | ei.attackedBy[c][ROOK] 
+      | ei.attackedBy[c][QUEEN] | ei.attackedBy[c][KING];
+  }
+
+  // Kings.  Kings are evaluated after all other pieces for both sides,
+  // because we need complete attack information for all pieces when computing
+  // the king safety evaluation.
+  for(Color c = WHITE; c <= BLACK; c++) {
+    s = pos.king_square(c);
+    evaluate_king(pos, s, c, ei);
+  }
+
+  // Evaluate passed pawns.  We evaluate passed pawns for both sides at once,
+  // because we need to know which side promotes first in positions where
+  // both sides have an unstoppable passed pawn.
+  if(ei.pi->passed_pawns())
+    evaluate_passed_pawns(pos, ei);
+
+  // Middle-game specific evaluation terms
+  if(phase > PHASE_ENDGAME) {
+
+    // Pawn storms in positions with opposite castling.
+    if(square_file(pos.king_square(WHITE)) >= FILE_E &&
+       square_file(pos.king_square(BLACK)) <= FILE_D)
+      ei.mgValue +=
+        ei.pi->queenside_storm_value(WHITE) -
+        ei.pi->kingside_storm_value(BLACK);
+    else if(square_file(pos.king_square(WHITE)) <= FILE_D &&
+            square_file(pos.king_square(BLACK)) >= FILE_E)
+      ei.mgValue += 
+        ei.pi->kingside_storm_value(WHITE) -
+        ei.pi->queenside_storm_value(BLACK);
+  }
+
+  // Mobility
+  ei.mgValue += apply_weight(ei.mgMobility, WeightMobilityMidgame);
+  ei.egValue += apply_weight(ei.egMobility, WeightMobilityEndgame);
+
+  // If we don't already have an unusual scale factor, check for opposite
+  // colored bishop endgames, and use a lower scale for those:
+  if(phase < PHASE_MIDGAME && pos.opposite_colored_bishops()
+     && ((factor[WHITE] == SCALE_FACTOR_NORMAL && ei.egValue > Value(0)) ||
+         (factor[BLACK] == SCALE_FACTOR_NORMAL && ei.egValue < Value(0)))) {
+    if(pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) ==
+       2*BishopValueMidgame) {
+      // Only the two bishops
+      if(pos.pawn_count(WHITE) + pos.pawn_count(BLACK) == 1) {
+        // KBP vs KB with only a single pawn; almost certainly a draw.
+        if(factor[WHITE] == SCALE_FACTOR_NORMAL)
+          factor[WHITE] = ScaleFactor(8);
+        if(factor[BLACK] == SCALE_FACTOR_NORMAL)
+          factor[BLACK] = ScaleFactor(8);
+      }
+      else {
+        // At least two pawns
+        if(factor[WHITE] == SCALE_FACTOR_NORMAL)
+          factor[WHITE] = ScaleFactor(32);
+        if(factor[BLACK] == SCALE_FACTOR_NORMAL)
+          factor[BLACK] = 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.
+      if(factor[WHITE] == SCALE_FACTOR_NORMAL)
+        factor[WHITE] = ScaleFactor(50);
+      if(factor[BLACK] == SCALE_FACTOR_NORMAL)
+        factor[BLACK] = ScaleFactor(50);
+    }
+  }
+
+  // Interpolate between the middle game and the endgame score, and
+  // return:
+  Value value = scale_by_game_phase(ei.mgValue, ei.egValue, phase, factor);
+
+  if(ei.mateThreat[stm] != MOVE_NONE)
+    return 8 * QueenValueMidgame - Sign[stm] * value;
+  else
+    return Sign[stm] * value;
+}
+
+
+/// quick_evaluate() does a very approximate evaluation of the current position.
+/// It currently considers only material and piece square table scores.  Perhaps
+/// we should add scores from the pawn and material hash tables?
+
+Value quick_evaluate(const Position &pos) {
+  Color stm;
+  Value mgValue, egValue;
+  ScaleFactor factor[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
+  Phase phase;
+  
+  assert(pos.is_ok());
+
+  stm = pos.side_to_move();
+
+  mgValue = pos.mg_value();
+  egValue = pos.eg_value();
+  phase = pos.game_phase();
+
+  Value value = scale_by_game_phase(mgValue, egValue, phase, factor);
+
+  return Sign[stm] * value;
+}
+  
+
+/// init_eval() initializes various tables used by the evaluation function.
+
+void init_eval(int threads) {
+  assert(threads <= THREAD_MAX);
+  
+  for(int i = 0; i < threads; i++) {
+    if(PawnTable[i] == NULL)
+      PawnTable[i] = new PawnInfoTable(PawnTableSize);
+    if(MaterialTable[i] == NULL)
+      MaterialTable[i] = new MaterialInfoTable(MaterialTableSize);
+  }
+  for(int i = threads; i < THREAD_MAX; i++) {
+    if(PawnTable[i] != NULL) {
+      delete PawnTable[i];
+      PawnTable[i] = NULL;
+    }
+    if(MaterialTable[i] != NULL) {
+      delete MaterialTable[i];
+      MaterialTable[i] = NULL;
+    }
+  }
+
+  for(Bitboard b = 0ULL; b < 256ULL; b++)
+    BitCount8Bit[b] = count_1s(b);
+}
+
+
+/// quit_eval() releases heap-allocated memory at program termination.
+
+void quit_eval() {
+  for(int i = 0; i < THREAD_MAX; i++) {
+    delete PawnTable[i];
+    delete MaterialTable[i];
+  }
+}
+
+
+/// read_weights() reads evaluation weights from the corresponding UCI
+/// parameters.
+
+void read_weights(Color sideToMove) {
+  WeightMobilityMidgame =
+    compute_weight(get_option_value_int("Mobility (Middle Game)"),
+                   WeightMobilityMidgameInternal);
+  WeightMobilityEndgame =
+    compute_weight(get_option_value_int("Mobility (Endgame)"),
+                   WeightMobilityEndgameInternal);
+  WeightPawnStructureMidgame =
+    compute_weight(get_option_value_int("Pawn Structure (Middle Game)"),
+                   WeightPawnStructureMidgameInternal);
+  WeightPawnStructureEndgame =
+    compute_weight(get_option_value_int("Pawn Structure (Endgame)"),
+                   WeightPawnStructureEndgameInternal);
+  WeightPassedPawnsMidgame =
+    compute_weight(get_option_value_int("Passed Pawns (Middle Game)"),
+                   WeightPassedPawnsMidgameInternal);
+  WeightPassedPawnsEndgame =
+    compute_weight(get_option_value_int("Passed Pawns (Endgame)"),
+                   WeightPassedPawnsEndgameInternal);
+  WeightKingSafety[sideToMove] =
+    compute_weight(get_option_value_int("Cowardice"), WeightKingSafetyInternal);
+  WeightKingSafety[opposite_color(sideToMove)] =
+    compute_weight(get_option_value_int("Aggressiveness"),
+                   WeightKingSafetyInternal);
+  WeightKingSafety[opposite_color(sideToMove)] =
+    (get_option_value_int("Aggressiveness") * 0x100) / 100;
+
+  init_safety();
+}
+
+
+namespace {
+
+  // evaluate_knight() assigns bonuses and penalties to a knight of a given
+  // color on a given square.
+  
+  void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) {
+
+    Color them = opposite_color(us);
+    Bitboard b = p.knight_attacks(s);
+    ei.attackedBy[us][KNIGHT] |= b;
+
+    // King attack
+    if(b & ei.attackZone[us]) {
+      ei.attackCount[us]++;
+      ei.attackWeight[us] += KnightAttackWeight;
+      Bitboard bb = (b & ei.attackedBy[them][KING]);
+      if(bb) ei.attacked[us] += count_1s_max_15(bb);
+    }
+        
+    // Mobility
+    int mob = count_1s_max_15(b & ~p.pieces_of_color(us));
+    ei.mgMobility += Sign[us] * MidgameKnightMobilityBonus[mob];
+    ei.egMobility += Sign[us] * EndgameKnightMobilityBonus[mob];
+
+    // Knight outposts:
+    if(p.square_is_weak(s, them)) {
+      Value v, bonus;
+      
+      // Initial bonus based on square:
+      v = bonus = KnightOutpostBonus[relative_square(us, s)];
+
+      // Increase bonus if supported by pawn, especially if the opponent has
+      // no minor piece which can exchange the outpost piece:
+      if(v && p.pawn_attacks(them, s) & p.pawns(us)) {
+        bonus += v/2;
+        if(p.knight_count(them) == 0 &&
+           (SquaresByColorBB[square_color(s)] &
+            p.bishops(them)) == EmptyBoardBB) {
+          bonus += v;
+        }
+      }
+
+      ei.mgValue += Sign[us] * bonus;
+      ei.egValue += Sign[us] * bonus;
+    }
+  }
+
+
+  // evaluate_bishop() assigns bonuses and penalties to a bishop of a given
+  // color on a given square.
+  
+  void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei) {
+
+    Color them = opposite_color(us);
+    Bitboard b =
+      bishop_attacks_bb(s, p.occupied_squares() & ~p.queens(us));
+                                   
+    ei.attackedBy[us][BISHOP] |= b;
+
+    // King attack
+    if(b & ei.attackZone[us]) {
+      ei.attackCount[us]++;
+      ei.attackWeight[us] += BishopAttackWeight;
+      Bitboard bb = (b & ei.attackedBy[them][KING]);
+      if(bb) ei.attacked[us] += count_1s_max_15(bb);
+    }
+
+    // Mobility:
+    int mob = count_1s_max_15(b & ~p.pieces_of_color(us));
+    ei.mgMobility += Sign[us] * MidgameBishopMobilityBonus[mob];
+    ei.egMobility += Sign[us] * EndgameBishopMobilityBonus[mob];
+
+    // Bishop outposts:
+    if(p.square_is_weak(s, them)) {
+      Value v, bonus;
+      
+      // Initial bonus based on square:
+      v = bonus = BishopOutpostBonus[relative_square(us, s)];
+
+      // Increase bonus if supported by pawn, especially if the opponent has
+      // no minor piece which can exchange the outpost piece:
+      if(v && p.pawn_attacks(them, s) & p.pawns(us)) {
+        bonus += v/2;
+        if(p.knight_count(them) == 0 &&
+           (SquaresByColorBB[square_color(s)] &
+            p.bishops(them)) == EmptyBoardBB) {
+          bonus += v;
+        }
+      }
+
+      ei.mgValue += Sign[us] * bonus;
+      ei.egValue += Sign[us] * bonus;
+    }    
+  }
+  
+
+  // evaluate_rook() assigns bonuses and penalties to a rook of a given
+  // color on a given square.
+  
+  void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei) {
+
+    Color them = opposite_color(us);
+    
+    // Open and half-open files:
+    File f = square_file(s);
+    if(ei.pi->file_is_half_open(us, f)) {
+      if(ei.pi->file_is_half_open(them, f)) {
+        ei.mgValue += Sign[us] * RookOpenFileBonus;
+        ei.egValue += Sign[us] * RookOpenFileBonus;
+      }
+      else {
+        ei.mgValue += Sign[us] * RookHalfOpenFileBonus;
+        ei.egValue += Sign[us] * RookHalfOpenFileBonus;
+      }
+    }
+
+    // Rook on 7th rank:
+    if(pawn_rank(us, s) == RANK_7 &&
+       pawn_rank(us, p.king_square(them)) == RANK_8) {
+      ei.mgValue += Sign[us] * MidgameRookOn7thBonus;
+      ei.egValue += Sign[us] * EndgameRookOn7thBonus;
+    }
+
+    //Bitboard b = p.rook_attacks(s);
+    Bitboard b =
+      rook_attacks_bb(s, p.occupied_squares() & ~p.rooks_and_queens(us));
+    ei.attackedBy[us][ROOK] |= b;
+
+    // King attack
+    if(b & ei.attackZone[us]) {
+      ei.attackCount[us]++;
+      ei.attackWeight[us] += RookAttackWeight;
+      Bitboard bb = (b & ei.attackedBy[them][KING]);
+      if(bb) ei.attacked[us] += count_1s_max_15(bb);
+    }
+
+    // Mobility
+    int mob = count_1s_max_15(b & ~p.pieces_of_color(us));
+    ei.mgMobility += Sign[us] * MidgameRookMobilityBonus[mob];
+    ei.egMobility += Sign[us] * EndgameRookMobilityBonus[mob];
+
+    // Penalize rooks which are trapped inside a king which has lost the
+    // right to castle:
+    if(mob <= 6 && !ei.pi->file_is_half_open(us, f)) {
+      Square ksq = p.king_square(us);
+      if(square_file(ksq) >= FILE_E && square_file(s) > square_file(ksq) &&
+         (pawn_rank(us, ksq) == RANK_1 || square_rank(ksq) == square_rank(s))) {
+        // Is there a half-open file between the king and the edge of the
+        // board?
+        if(!(ei.pi->has_open_file_to_right(us, square_file(ksq)))) {
+          ei.mgValue -= p.can_castle(us)?
+            Sign[us] * ((TrappedRookPenalty - mob * 16) / 2) :
+            Sign[us] * (TrappedRookPenalty - mob * 16);
+        }
+      }
+      else if(square_file(ksq) <= FILE_D && square_file(s) < square_file(ksq)
+              && (pawn_rank(us, ksq) == RANK_1 ||
+                  square_rank(ksq) == square_rank(s))) {
+        // Is there a half-open file between the king and the edge of the
+        // board?
+        if(!(ei.pi->has_open_file_to_left(us, square_file(ksq)))) {
+          ei.mgValue -= p.can_castle(us)?
+            Sign[us] * ((TrappedRookPenalty - mob * 16) / 2) :
+            Sign[us] * (TrappedRookPenalty - mob * 16);
+        }
+      }
+    }
+  }
+
+
+  // evaluate_queen() assigns bonuses and penalties to a queen of a given
+  // color on a given square.
+  
+  void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) {
+
+    Color them = opposite_color(us);
+
+    // Queen on 7th rank:
+    if(pawn_rank(us, s) == RANK_7 &&
+       pawn_rank(us, p.king_square(them)) == RANK_8) {
+      ei.mgValue += Sign[us] * MidgameQueenOn7thBonus;
+      ei.egValue += Sign[us] * EndgameQueenOn7thBonus;
+    }
+
+    Bitboard b = p.queen_attacks(s);
+    ei.attackedBy[us][QUEEN] |= b;
+
+    // King attack
+    if(b & ei.attackZone[us]) {
+      ei.attackCount[us]++;
+      ei.attackWeight[us] += QueenAttackWeight;
+      Bitboard bb = (b & ei.attackedBy[them][KING]);
+      if(bb) ei.attacked[us] += count_1s_max_15(bb);
+    }
+    
+    // Mobility
+    int mob = count_1s(b & ~p.pieces_of_color(us));
+    ei.mgMobility += Sign[us] * MidgameQueenMobilityBonus[mob];
+    ei.egMobility += Sign[us] * EndgameQueenMobilityBonus[mob];
+  }
+
+
+  // evaluate_king() assigns bonuses and penalties to a king of a given
+  // color on a given square.
+  
+  void evaluate_king(const Position &p, Square s, Color us, EvalInfo &ei) {
+    
+    int shelter = 0, sign = Sign[us];
+
+    // King shelter.
+    if(pawn_rank(us, s) <= RANK_4) {
+      Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
+      Rank r = square_rank(s);
+      for(int i = 0; i < 3; i++)
+        shelter += count_1s_8bit(pawns >> ((r+(i+1)*sign) * 8)) * (64>>i);
+      ei.mgValue += sign * Value(shelter);
+    }
+
+    // King safety.  This is quite complicated, and is almost certainly far
+    // from optimally tuned.  
+    Color them = opposite_color(us);
+    if(p.queen_count(them) >= 1 && ei.attackCount[them] >= 2
+       && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame
+       && ei.attacked[them]) {
+
+      // Is it the attackers turn to move?
+      bool sente = (them == p.side_to_move());
+      
+      // Find the attacked squares around the king which has no defenders
+      // apart from the king itself:
+      Bitboard undefended =
+        ei.attacked_by(them) & ~ei.attacked_by(us, PAWN)
+        & ~ei.attacked_by(us, KNIGHT) & ~ei.attacked_by(us, BISHOP)
+        & ~ei.attacked_by(us, ROOK) & ~ei.attacked_by(us, QUEEN)
+        & ei.attacked_by(us, KING);
+      Bitboard occ = p.occupied_squares(), b, b2;
+
+      // Initialize the 'attackUnits' variable, which is used later on as an
+      // index to the SafetyTable[] array.  The initial is based on the number
+      // and types of the attacking pieces, the number of attacked and
+      // undefended squares around the king, the square of the king, and the
+      // quality of the pawn shelter.
+      int attackUnits =
+        Min((ei.attackCount[them] * ei.attackWeight[them]) / 2, 25)
+        + (ei.attacked[them] + count_1s_max_15(undefended)) * 3
+        + InitKingDanger[relative_square(us, s)] - shelter / 32;
+
+      // Analyse safe queen contact checks:
+      b = undefended & ei.attacked_by(them, QUEEN) & ~p.pieces_of_color(them);
+      if(b) {
+        Bitboard attackedByOthers =
+          ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
+          | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK);
+        b &= attackedByOthers;
+        if(b) {
+          // The bitboard b now contains the squares available for safe queen
+          // contact checks.
+          int count = count_1s_max_15(b);
+          attackUnits += QueenContactCheckBonus * count * (sente? 2 : 1);
+
+          // Is there a mate threat?
+          if(QueenContactMates && !p.is_check()) {
+            Bitboard escapeSquares =
+              p.king_attacks(s) & ~p.pieces_of_color(us) & ~attackedByOthers;
+            while(b) {
+              Square from, to = pop_1st_bit(&b);
+              if(!(escapeSquares
+                   & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) {
+                // We have a mate, unless the queen is pinned or there
+                // is an X-ray attack through the queen.
+                for(int i = 0; i < p.queen_count(them); i++) {
+                  from = p.queen_list(them, i);
+                  if(bit_is_set(p.queen_attacks(from), to)
+                     && !bit_is_set(p.pinned_pieces(them), from)
+                     && !(rook_attacks_bb(to, occ & clear_mask_bb(from))
+                          & p.rooks_and_queens(us))
+                     && !(rook_attacks_bb(to, occ & clear_mask_bb(from))
+                          & p.rooks_and_queens(us)))
+                    ei.mateThreat[them] = make_move(from, to);
+                }
+              }
+            }
+          }
+        }
+      }
+
+      // Analyse safe rook contact checks:
+      if(RookContactCheckBonus) {
+        b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them);
+        if(b) {
+          Bitboard attackedByOthers =
+            ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
+            | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN);
+          b &= attackedByOthers;
+          if(b) {
+            int count = count_1s_max_15(b);
+            attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1));
+          }
+        }
+      }
+      
+      // Analyse safe distance checks:
+      if(QueenCheckBonus > 0 || RookCheckBonus > 0) {
+        b = p.rook_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+
+        // Queen checks
+        b2 = b & ei.attacked_by(them, QUEEN);
+        if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2);
+
+        // Rook checks
+        b2 = b & ei.attacked_by(them, ROOK);
+        if(b2) attackUnits += RookCheckBonus * count_1s_max_15(b2);
+      }
+      if(QueenCheckBonus > 0 || BishopCheckBonus > 0) {
+        b = p.bishop_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+        // Queen checks
+        b2 = b & ei.attacked_by(them, QUEEN);
+        if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2);
+
+        // Bishop checks
+        b2 = b & ei.attacked_by(them, BISHOP);
+        if(b2) attackUnits += BishopCheckBonus * count_1s_max_15(b2);
+      }
+      if(KnightCheckBonus > 0) {
+        b = p.knight_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+        // Knight checks
+        b2 = b & ei.attacked_by(them, KNIGHT);
+        if(b2) attackUnits += KnightCheckBonus * count_1s_max_15(b2);
+      }
+
+      // Analyse discovered checks (only for non-pawns right now, consider
+      // adding pawns later).
+      if(DiscoveredCheckBonus) {
+        b = p.discovered_check_candidates(them) & ~p.pawns();
+        if(b)
+          attackUnits +=
+            DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1);
+      }
+
+      // Has a mate threat been found?  We don't do anything here if the
+      // side with the mating move is the side to move, because in that
+      // case the mating side will get a huge bonus at the end of the main
+      // evaluation function instead.
+      if(ei.mateThreat[them] != MOVE_NONE)
+        attackUnits += MateThreatBonus;
+
+      // Ensure that attackUnits is between 0 and 99, in order to avoid array
+      // out of bounds errors:
+      if(attackUnits < 0) attackUnits = 0;
+      if(attackUnits >= 100) attackUnits = 99;
+
+      // Finally, extract the king safety score from the SafetyTable[] array.
+      // Add the score to the evaluation, and also to ei.futilityMargin.  The
+      // reason for adding the king safety score to the futility margin is
+      // that the king safety scores can sometimes be very big, and that
+      // capturing a single attacking piece can therefore result in a score
+      // change far bigger than the value of the captured piece.
+      Value v = apply_weight(SafetyTable[attackUnits], WeightKingSafety[us]);
+      ei.mgValue -= sign * v;
+      if(us == p.side_to_move())
+        ei.futilityMargin += v;
+    }
+  }
+
+
+  // evaluate_passed_pawns() evaluates the passed pawns for both sides.
+
+  void evaluate_passed_pawns(const Position &pos, EvalInfo &ei) {
+    bool hasUnstoppable[2] = {false, false};
+    int movesToGo[2] = {100, 100};
+
+    for(Color us = WHITE; us <= BLACK; us++) {
+      Color them = opposite_color(us);
+      Square ourKingSq = pos.king_square(us);
+      Square theirKingSq = pos.king_square(them);
+      Bitboard b = ei.pi->passed_pawns() & pos.pawns(us), b2, b3, b4;
+
+      while(b) {
+        Square s = pop_1st_bit(&b);
+        assert(pos.piece_on(s) == pawn_of_color(us));
+        assert(pos.pawn_is_passed(us, s));
+
+        int r = int(pawn_rank(us, s) - RANK_2);
+        int tr = Max(0, r * (r-1));
+        Square blockSq = s + pawn_push(us);
+
+        // Base bonus based on rank:
+        Value mbonus = Value(20 * tr);
+        Value ebonus = Value(10 + r * r * 10);
+
+        // Adjust bonus based on king proximity:
+        ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
+        ebonus -=
+          Value(square_distance(ourKingSq, blockSq + pawn_push(us)) * 1 * tr);
+        ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
+
+        // If the pawn is free to advance, increase bonus:
+        if(pos.square_is_empty(blockSq)) {
+
+          b2 = squares_in_front_of(us, s);
+          b3 = b2 & ei.attacked_by(them);
+          b4 = b2 & ei.attacked_by(us);
+          if((b2 & pos.pieces_of_color(them)) == EmptyBoardBB) {
+            // There are no enemy pieces in the pawn's path!  Are any of the
+            // squares in the pawn's path attacked by the enemy?
+            if(b3 == EmptyBoardBB)
+              // No enemy attacks, huge bonus!
+              ebonus += Value(tr * ((b2 == b4)? 17 : 15));
+            else
+              // OK, there are enemy attacks.  Are those squares which are
+              // attacked by the enemy also attacked by us?  If yes, big bonus
+              // (but smaller than when there are no enemy attacks), if no,
+              // somewhat smaller bonus.
+              ebonus += Value(tr * (((b3 & b4) == b3)? 13 : 8));
+          }
+          else {
+            // There are some enemy pieces in the pawn's path.  While this is
+            // sad, we still assign a moderate bonus if all squares in the path
+            // which are either occupied by or attacked by enemy pieces are
+            // also attacked by us.
+            if(((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
+              ebonus += Value(tr * 6);
+          }
+          // At last, add a small bonus when there are no *friendly* pieces
+          // in the pawn's path:
+          if((b2 & pos.pieces_of_color(us)) == EmptyBoardBB)
+            ebonus += Value(tr);
+        }
+
+        // If the pawn is supported by a friendly pawn, increase bonus.
+        b2 = pos.pawns(us) & neighboring_files_bb(s);
+        if(b2 & rank_bb(s))
+          ebonus += Value(r * 20);
+        else if(pos.pawn_attacks(them, s) & b2)
+          ebonus += Value(r * 12);
+
+        // If the other side has only a king, check whether the pawn is
+        // unstoppable:
+        if(pos.non_pawn_material(them) == Value(0)) {
+          Square qsq;
+          int d;
+
+          qsq = relative_square(us, make_square(square_file(s), RANK_8));
+          d = square_distance(s, qsq) - square_distance(theirKingSq, qsq)
+            + ((us == pos.side_to_move())? 0 : 1);
+
+          if(d < 0) {
+            int mtg = RANK_8 - pawn_rank(us, s);
+            int blockerCount =
+              count_1s_max_15(squares_in_front_of(us,s)&pos.occupied_squares());
+            mtg += blockerCount;
+            d += blockerCount;
+            if(d < 0) {
+              hasUnstoppable[us] = true;
+              movesToGo[us] = Min(movesToGo[us], mtg);
+            }
+          }
+        }
+        // Rook pawns are a special case:  They are sometimes worse, and
+        // sometimes better than other passed pawns.  It is difficult to find
+        // good rules for determining whether they are good or bad.  For now,
+        // we try the following:  Increase the value for rook pawns if the
+        // other side has no pieces apart from a knight, and decrease the
+        // value if the other side has a rook or queen.
+        if(square_file(s) == FILE_A || square_file(s) == FILE_H) {
+          if(pos.non_pawn_material(them) == KnightValueMidgame
+             && pos.knight_count(them) == 1)
+            ebonus += ebonus / 4;
+          else if(pos.rooks_and_queens(them))
+            ebonus -= ebonus / 4;
+        }
+
+        // Add the scores for this pawn to the middle game and endgame eval.
+        ei.mgValue += apply_weight(Sign[us] * mbonus, WeightPassedPawnsMidgame);
+        ei.egValue += apply_weight(Sign[us] * ebonus, WeightPassedPawnsEndgame);
+      }
+    }
+
+    // Does either side have an unstoppable passed pawn?
+    if(hasUnstoppable[WHITE] && !hasUnstoppable[BLACK])
+      ei.egValue += UnstoppablePawnValue - Value(0x40 * movesToGo[WHITE]);
+    else if(hasUnstoppable[BLACK] && !hasUnstoppable[WHITE])
+      ei.egValue -= UnstoppablePawnValue - Value(0x40 * movesToGo[BLACK]);
+    else if(hasUnstoppable[BLACK] && hasUnstoppable[WHITE]) {
+      // Both sides have unstoppable pawns!  Try to find out who queens
+      // first.  We begin by transforming 'movesToGo' to the number of
+      // plies until the pawn queens for both sides:
+      movesToGo[WHITE] *= 2;
+      movesToGo[BLACK] *= 2;
+      movesToGo[pos.side_to_move()]--;
+
+      // If one side queens at least three plies before the other, that
+      // side wins:
+      if(movesToGo[WHITE] <= movesToGo[BLACK] - 3)
+        ei.egValue += UnstoppablePawnValue - Value(0x40 * (movesToGo[WHITE]/2));
+      else if(movesToGo[BLACK] <= movesToGo[WHITE] - 3)
+        ei.egValue -= UnstoppablePawnValue - Value(0x40 * (movesToGo[BLACK]/2));
+
+      // We could also add some rules about the situation when one side
+      // queens exactly one ply before the other:  Does the first queen
+      // check the opponent's king, or attack the opponent's queening square?
+      // This is slightly tricky to get right, because it is possible that
+      // the opponent's king has moved somewhere before the first pawn queens.
+    }
+  }
+
+
+  // evaluate_trapped_bishop_a7h7() determines whether a bishop on a7/h7
+  // (a2/h2 for black) is trapped by enemy pawns, and assigns a penalty
+  // if it is.
+  
+  void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
+                                    EvalInfo &ei) {
+    Piece pawn = pawn_of_color(opposite_color(us));
+    Square b6, b8;
+
+    assert(square_is_ok(s));
+    assert(pos.piece_on(s) == bishop_of_color(us));
+
+    if(square_file(s) == FILE_A) {
+      b6 = relative_square(us, SQ_B6);
+      b8 = relative_square(us, SQ_B8);
+    }
+    else {
+      b6 = relative_square(us, SQ_G6);
+      b8 = relative_square(us, SQ_G8);
+    }
+
+    if(pos.piece_on(b6) == pawn && pos.see(s, b6) < 0 && pos.see(s, b8) < 0) {
+      ei.mgValue -= Sign[us] * TrappedBishopA7H7Penalty;
+      ei.egValue -= Sign[us] * TrappedBishopA7H7Penalty;
+    }
+
+  }
+
+
+  // evaluate_trapped_bishop_a1h1() determines whether a bishop on a1/h1
+  // (a8/h8 for black) is trapped by a friendly pawn on b2/g2 (b7/g7 for
+  // black), and assigns a penalty if it is.  This pattern can obviously
+  // only occur in Chess960 games.
+  
+  void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us,
+                                    EvalInfo &ei) {
+    Piece pawn = pawn_of_color(us);
+    Square b2, b3, c3;
+
+    assert(Chess960);
+    assert(square_is_ok(s));
+    assert(pos.piece_on(s) == bishop_of_color(us));
+
+    if(square_file(s) == FILE_A) {
+      b2 = relative_square(us, SQ_B2);
+      b3 = relative_square(us, SQ_B3);
+      c3 = relative_square(us, SQ_C3);
+    }
+    else {
+      b2 = relative_square(us, SQ_G2);
+      b3 = relative_square(us, SQ_G3);
+      c3 = relative_square(us, SQ_F3);
+    }
+
+    if(pos.piece_on(b2) == pawn) {
+      Value penalty;
+
+      if(!pos.square_is_empty(b3))
+        penalty = 2*TrappedBishopA1H1Penalty;
+      else if(pos.piece_on(c3) == pawn)
+        penalty = TrappedBishopA1H1Penalty;
+      else
+        penalty = TrappedBishopA1H1Penalty / 2;
+      
+      ei.mgValue -= Sign[us] * penalty;
+      ei.egValue -= Sign[us] * penalty;
+    }
+
+  }
+
+
+  // apply_weight applies an evaluation weight to a value.
+
+  inline Value apply_weight(Value v, int w) {
+    return (v*w) / 0x100;
+  }
+
+
+  // scale_by_game_phase interpolates between a middle game and an endgame
+  // score, based on game phase.  It also scales the return value by a
+  // ScaleFactor array.
+  
+  Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]) {
+    assert(mv > -VALUE_INFINITE && mv < VALUE_INFINITE);
+    assert(ev > -VALUE_INFINITE && ev < VALUE_INFINITE);
+    assert(ph >= PHASE_ENDGAME && ph <= PHASE_MIDGAME);
+
+    if(ev > Value(0))
+      ev = apply_scale_factor(ev, sf[WHITE]);
+    else
+      ev = apply_scale_factor(ev, sf[BLACK]);
+
+    Value result = Value(int((mv * ph + ev * (128 - ph)) / 128));
+    return Value(int(result) & ~(GrainSize - 1));
+  }
+
+
+  // count_1s_8bit() counts the number of nonzero bits in the 8 least
+  // significant bits of an integer.  This function is used by the king
+  // shield evaluation.
+  
+  int count_1s_8bit(int b) {
+    return int(BitCount8Bit[b & 0xFF]);
+  }
+
+
+  // compute_weight() computes the value of an evaluation weight, by combining
+  // an UCI-configurable weight with an internal weight.
+
+  int compute_weight(int uciWeight, int internalWeight) {
+    uciWeight = (uciWeight * 0x100) / 100;
+    return (uciWeight * internalWeight) / 0x100;
+  }
+  
+
+  // init_safety() initizes the king safety evaluation, based on UCI
+  // parameters.  It is called from read_weights().
+  
+  void init_safety() {
+    double a, b;
+    int maxSlope, peak, i, j;
+    
+    QueenContactCheckBonus = get_option_value_int("Queen Contact Check Bonus");
+    RookContactCheckBonus = get_option_value_int("Rook Contact Check Bonus");
+    QueenCheckBonus = get_option_value_int("Queen Check Bonus");
+    RookCheckBonus = get_option_value_int("Rook Check Bonus");
+    BishopCheckBonus = get_option_value_int("Bishop Check Bonus");
+    KnightCheckBonus = get_option_value_int("Knight Check Bonus");
+    DiscoveredCheckBonus = get_option_value_int("Discovered Check Bonus");
+    MateThreatBonus = get_option_value_int("Mate Threat Bonus");
+
+    a = get_option_value_int("King Safety Coefficient") / 100.0;
+    b = get_option_value_int("King Safety X Intercept") * 1.0;
+    maxSlope = get_option_value_int("King Safety Max Slope");
+    peak = (get_option_value_int("King Safety Max Value") * 256) / 100;
+    
+    for(i = 0; i < 100; i++) {
+      if(i < b) SafetyTable[i] = Value(0);
+      else if(get_option_value_string("King Safety Curve") == "Quadratic")
+        SafetyTable[i] = Value((int)(a * (i - b) * (i - b)));
+      else if(get_option_value_string("King Safety Curve") == "Linear")
+        SafetyTable[i] = Value((int)(100 * a * (i - b)));
+    }
+
+    for(i = 0; i < 100; i++)
+      if(SafetyTable[i+1] - SafetyTable[i] > maxSlope) {
+        for(j = i + 1; j < 100; j++)
+          SafetyTable[j] = SafetyTable[j-1] + Value(maxSlope);
+      }
+    for(i = 0; i < 100; i++)
+      if(SafetyTable[i]  > Value(peak))
+        SafetyTable[i] = Value(peak);
+  }
+  
+}
diff --git a/src/evaluate.h b/src/evaluate.h
new file mode 100644 (file)
index 0000000..8662f4b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(EVALUATE_H_INCLUDED)
+#define EVALUATE_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "material.h"
+#include "pawns.h"
+#include "position.h"
+
+
+////
+//// Types
+////
+
+/// The EvalInfo struct contains various information computed and collected
+/// by the evaluation function.  An EvalInfo object is passed as one of the
+/// arguments to the evaluation function, and the search can make use of its
+/// contents to make intelligent search decisions.
+///
+/// At the moment, this is not utilized very much:  The only part of the
+/// EvalInfo object which is used by the search is futilityMargin.
+
+struct EvalInfo {
+  
+  // Middle game and endgame evaluations:
+  Value mgValue, egValue;
+
+  // Pointers to material and pawn hash table entries:
+  MaterialInfo *mi;
+  PawnInfo *pi;
+
+  // attackedBy[color][piece type] is a bitboard representing all squares
+  // attacked by a given color and piece type.  attackedBy[color][0] contains
+  // all squares attacked by the given color.
+  Bitboard attackedBy[2][8];
+  Bitboard attacked_by(Color c) const { return attackedBy[c][0]; }
+  Bitboard attacked_by(Color c, PieceType pt) const { return attackedBy[c][pt]; }
+  // attackZone[color] is the zone around the enemy king which is considered
+  // by the king safety evaluation.  This consists of the squares directly
+  // adjacent to the king, and the three (or two, for a king on an edge file)
+  // squares two ranks in front of the king.  For instance, if black's king
+  // is on g8, attackZone[WHITE] is a bitboard containing the squares f8, h8,
+  // f7, g7, h7, f6, g6 and h6.
+  Bitboard attackZone[2];
+
+  // attackCount[color] is the number of pieces of the given color which
+  // attack a square adjacent to the enemy king.
+  int attackCount[2];
+
+  // attackWeight[color] is the sum of the "weight" of the pieces of the given
+  // color which attack a square adjacent to the enemy king.  The weights of
+  // the individual piece types are given by the variables QueenAttackWeight,
+  // RookAttackWeight, BishopAttackWeight and KnightAttackWeight in
+  // evaluate.cpp.
+  int attackWeight[2];
+
+  // attacked[color] is the number of enemy piece 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 attacked[BLACK].
+  int attacked[2];
+
+  // mateThreat[color] is a move for the given side which gives a direct mate.
+  Move mateThreat[2];
+
+  // Middle game and endgame mobility scores.
+  Value mgMobility, egMobility;
+
+  // Extra futility margin.  This is added to the standard futility margin
+  // in the quiescence search.  
+  Value futilityMargin;
+};
+
+
+////
+//// Prototypes
+////
+
+extern Value evaluate(const Position &pos, EvalInfo &ei, int threadID);
+extern Value quick_evaluate(const Position &pos);
+extern void init_eval(int threads);
+extern void quit_eval();
+extern void read_weights(Color sideToMove);
+
+
+#endif // !defined(EVALUATE_H_INCLUDED)
diff --git a/src/history.cpp b/src/history.cpp
new file mode 100644 (file)
index 0000000..2963148
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+
+#include "history.h"
+
+
+////
+//// Functions
+////
+
+/// Constructor
+
+History::History() {
+  this->clear();
+}
+
+
+/// History::clear() clears the history tables.
+
+void History::clear() {
+  memset(history, 0, 2 * 8 * 64 * sizeof(int));
+  memset(successCount, 0, 2 * 8 * 64 * sizeof(int));
+  memset(failureCount, 0, 2 * 8 * 64 * sizeof(int));
+}
+
+
+/// History::success() registers a move as being successful.  This is done
+/// whenever a non-capturing move causes a beta cutoff in the main search.
+/// The three parameters are the moving piece, the move itself, and the
+/// search depth.
+
+void History::success(Piece p, Move m, Depth d) {
+  assert(piece_is_ok(p));
+  assert(move_is_ok(m));
+
+  history[p][move_to(m)] += int(d) * int(d);
+  successCount[p][move_to(m)]++;
+
+  // Prevent history overflow:
+  if(history[p][move_to(m)] >= HistoryMax)
+    for(int i = 0; i < 16; i++)
+      for(int j = 0; j < 64; j++)
+        history[i][j] /= 2;
+}
+
+
+/// History::failure() registers a move as being unsuccessful.  The function is
+/// called for each non-capturing move which failed to produce a beta cutoff
+/// at a node where a beta cutoff was finally found.
+
+void History::failure(Piece p, Move m) {
+  assert(piece_is_ok(p));
+  assert(move_is_ok(m));
+
+  failureCount[p][move_to(m)]++;
+}
+
+
+/// History::move_ordering_score() returns an integer value used to order the
+/// non-capturing moves in the MovePicker class.
+
+int History::move_ordering_score(Piece p, Move m) const {
+  assert(piece_is_ok(p));
+  assert(move_is_ok(m));
+
+  return history[p][move_to(m)];
+}
+
+
+/// History::ok_to_prune() decides whether a move has been sufficiently
+/// unsuccessful that it makes sense to prune it entirely. 
+
+bool History::ok_to_prune(Piece p, Move m, Depth d) const {
+  assert(piece_is_ok(p));
+  assert(move_is_ok(m));
+
+  return (int(d) * successCount[p][move_to(m)] < failureCount[p][move_to(m)]);
+}
diff --git a/src/history.h b/src/history.h
new file mode 100644 (file)
index 0000000..ced416a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(HISTORY_H_INCLUDED)
+#define HISTORY_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "depth.h"
+#include "move.h"
+#include "piece.h"
+
+
+////
+//// Types
+////
+
+/// The History class stores statistics about how often different moves have
+/// been successful or unsuccessful during the current search.  These
+/// statistics are used for reduction and move ordering decisions.
+
+class History {
+
+public:
+  History();
+  void clear();
+  void success(Piece p, Move m, Depth d);
+  void failure(Piece p, Move m);
+  int move_ordering_score(Piece p, Move m) const;
+  bool ok_to_prune(Piece p, Move m, Depth d) const;
+
+private:
+  int history[16][64];  // [piece][square]
+  int successCount[16][64];
+  int failureCount[16][64];
+};
+
+
+////
+//// Constants and variables
+////
+
+/// HistoryMax controls how often the history counters will be scaled down:
+/// When the history score for a move gets bigger than HistoryMax, all
+/// entries in the table are divided by 2.  It is difficult to guess what
+/// the ideal value of this constant is.  Scaling down the scores often has
+/// the effect that parts of the search tree which have been searched
+/// recently have a bigger importance for move ordering than the moves which
+/// have been searched a long time ago.
+///
+/// Note that HistoryMax should probably be changed whenever the constant
+/// OnePly in depth.h is changed.  This is somewhat annoying.  Perhaps it
+/// would be better to scale down the history table at regular intervals?
+
+const int HistoryMax = 50000;
+
+
+#endif // !defined(HISTORY_H_INCLUDED)
diff --git a/src/lock.h b/src/lock.h
new file mode 100644 (file)
index 0000000..2efb207
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(LOCK_H_INCLUDED)
+#define LOCK_H_INCLUDED
+
+
+// x86 assembly language locks or OS spin locks may perform faster than
+// mutex locks on some platforms.  On my machine, mutexes seem to be the
+// best.
+
+//#define ASM_LOCK
+//#define OS_SPIN_LOCK
+
+
+#if defined(ASM_LOCK)
+
+
+typedef volatile int Lock;
+
+static inline void LockX86(Lock *lock) {
+  int dummy;
+  asm __volatile__("1:          movl    $1, %0" "\n\t"
+      "            xchgl   (%1), %0" "\n\t" "            testl   %0, %0" "\n\t"
+      "            jz      3f" "\n\t" "2:          pause" "\n\t"
+      "            movl    (%1), %0" "\n\t" "            testl   %0, %0" "\n\t"
+      "            jnz     2b" "\n\t" "            jmp     1b" "\n\t" "3:"
+      "\n\t":"=&q"(dummy)
+      :"q"(lock)
+      :"cc");
+}
+
+static inline void UnlockX86(Lock *lock) {
+  int dummy;
+  asm __volatile__("movl    $0, (%1)":"=&q"(dummy)
+      :"q"(lock));
+}
+
+#  define lock_init(x, y) (*(x) = 0)
+#  define lock_grab(x) LockX86(x)
+#  define lock_release(x) UnlockX86(x)
+#  define lock_destroy(x)
+
+
+#elif defined(OS_SPIN_LOCK)
+
+
+#  include <libkern/OSAtomic.h>
+
+typedef OSSpinLock Lock;
+
+#  define lock_init(x, y) (*(x) = 0)
+#  define lock_grab(x) OSSpinLockLock(x)
+#  define lock_release(x) OSSpinLockUnlock(x)
+#  define lock_destroy(x)
+
+
+#elif !defined(_MSC_VER)
+
+#  include <pthread.h>
+
+typedef pthread_mutex_t Lock;
+
+#  define lock_init(x, y) pthread_mutex_init(x, y)
+#  define lock_grab(x) pthread_mutex_lock(x)
+#  define lock_release(x) pthread_mutex_unlock(x)
+#  define lock_destroy(x) pthread_mutex_destroy(x)
+
+
+#else
+
+
+#  include <windows.h>
+
+typedef CRITICAL_SECTION Lock;
+#  define lock_init(x, y) InitializeCriticalSection(x)
+#  define lock_grab(x) EnterCriticalSection(x)
+#  define lock_release(x) LeaveCriticalSection(x)
+#  define lock_destroy(x) DeleteCriticalSection(x)
+
+
+#endif
+
+
+#endif // !defined(LOCK_H_INCLUDED)
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..49c66c0
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cstdlib>
+#include <iostream>
+
+#include "benchmark.h"
+#include "bitboard.h"
+#include "direction.h"
+#include "endgame.h"
+#include "evaluate.h"
+#include "material.h"
+#include "mersenne.h"
+#include "misc.h"
+#include "movepick.h"
+#include "position.h"
+#include "search.h"
+#include "thread.h"
+#include "uci.h"
+#include "ucioption.h"
+
+
+//// 
+//// Functions
+////
+
+int main(int argc, char *argv[]) {
+
+  // Disable IO buffering
+  setbuf(stdin, NULL);
+  setbuf(stdout, NULL);
+  std::cout.rdbuf()->pubsetbuf(NULL, 0);
+  std::cin.rdbuf()->pubsetbuf(NULL, 0);
+
+  // Initialization
+
+  init_mersenne();
+  init_direction_table();
+  init_bitboards();
+  init_uci_options();
+  Position::init_zobrist();
+  Position::init_piece_square_tables();
+  MaterialInfo::init();
+  MovePicker::init_phase_table();
+  init_eval(1);
+  init_bitbases();
+  init_threads();
+
+  // Make random number generation less deterministic, for book moves
+  int i = abs(get_system_time() % 10000);
+  for(int j = 0; j < i; j++)
+    genrand_int32();
+
+  // Process command line arguments
+  if(argc >= 2) {
+    if(std::string(argv[1]) == "bench") {
+      if(argc != 4) {
+        std::cout << "Usage: glaurung bench <hash> <threads>" << std::endl;
+        exit(0);
+      }
+      benchmark(std::string(argv[2]), std::string(argv[3]));
+      return 0;
+    }
+  }
+
+  // Print copyright notice
+  std::cout << engine_name() << ".  "
+            << "Copyright (C) 2004-2008 Tord Romstad."
+            << std::endl;
+
+  // Enter UCI mode
+  uci_main_loop();
+
+  return 0;
+}
diff --git a/src/material.cpp b/src/material.cpp
new file mode 100644 (file)
index 0000000..c7bb810
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+
+#include "material.h"
+
+
+////
+//// Local definitions
+////
+
+namespace {
+
+  const Value BishopPairMidgameBonus = Value(100);
+  const Value BishopPairEndgameBonus = Value(100);
+
+  Key KPKMaterialKey, KKPMaterialKey;
+  Key KBNKMaterialKey, KKBNMaterialKey;
+  Key KRKPMaterialKey, KPKRMaterialKey;
+  Key KRKBMaterialKey, KBKRMaterialKey;
+  Key KRKNMaterialKey, KNKRMaterialKey;
+  Key KQKRMaterialKey, KRKQMaterialKey;
+  Key KRPKRMaterialKey, KRKRPMaterialKey;
+  Key KRPPKRPMaterialKey, KRPKRPPMaterialKey;
+  Key KNNKMaterialKey, KKNNMaterialKey;
+  Key KBPKBMaterialKey, KBKBPMaterialKey;
+  Key KBPKNMaterialKey, KNKBPMaterialKey;
+  Key KNPKMaterialKey, KKNPMaterialKey;
+  Key KPKPMaterialKey;
+
+};
+
+
+////
+//// Functions
+////
+
+/// MaterialInfo::init() is called during program initialization.  It 
+/// precomputes material hash keys for a few basic endgames, in order
+/// to make it easy to recognize such endgames when they occur.
+
+void MaterialInfo::init() {
+  KPKMaterialKey = Position::zobMaterial[WHITE][PAWN][1];
+  KKPMaterialKey = Position::zobMaterial[BLACK][PAWN][1];
+  KBNKMaterialKey =
+    Position::zobMaterial[WHITE][BISHOP][1] ^
+    Position::zobMaterial[WHITE][KNIGHT][1];
+  KKBNMaterialKey =
+    Position::zobMaterial[BLACK][BISHOP][1] ^
+    Position::zobMaterial[BLACK][KNIGHT][1];
+  KRKPMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+  KPKRMaterialKey =
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[BLACK][ROOK][1];
+  KRKBMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[BLACK][BISHOP][1];
+  KBKRMaterialKey =
+    Position::zobMaterial[WHITE][BISHOP][1] ^
+    Position::zobMaterial[BLACK][ROOK][1];
+  KRKNMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[BLACK][KNIGHT][1];
+  KNKRMaterialKey =
+    Position::zobMaterial[WHITE][KNIGHT][1] ^
+    Position::zobMaterial[BLACK][ROOK][1];
+  KQKRMaterialKey =
+    Position::zobMaterial[WHITE][QUEEN][1] ^
+    Position::zobMaterial[BLACK][ROOK][1];
+  KRKQMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[BLACK][QUEEN][1];
+  KRPKRMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[BLACK][ROOK][1];
+  KRKRPMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[BLACK][ROOK][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+  KRPPKRPMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[WHITE][PAWN][2] ^
+    Position::zobMaterial[BLACK][ROOK][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+  KRPKRPPMaterialKey =
+    Position::zobMaterial[WHITE][ROOK][1] ^
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[BLACK][ROOK][1] ^
+    Position::zobMaterial[BLACK][PAWN][1] ^
+    Position::zobMaterial[BLACK][PAWN][2];
+  KNNKMaterialKey =
+    Position::zobMaterial[WHITE][KNIGHT][1] ^
+    Position::zobMaterial[WHITE][KNIGHT][2];
+  KKNNMaterialKey =
+    Position::zobMaterial[BLACK][KNIGHT][1] ^
+    Position::zobMaterial[BLACK][KNIGHT][2];
+  KBPKBMaterialKey =
+    Position::zobMaterial[WHITE][BISHOP][1] ^
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[BLACK][BISHOP][1];
+  KBKBPMaterialKey =
+    Position::zobMaterial[WHITE][BISHOP][1] ^
+    Position::zobMaterial[BLACK][BISHOP][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+  KBPKNMaterialKey =
+    Position::zobMaterial[WHITE][BISHOP][1] ^
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[BLACK][KNIGHT][1];
+  KNKBPMaterialKey =
+    Position::zobMaterial[WHITE][KNIGHT][1] ^
+    Position::zobMaterial[BLACK][BISHOP][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+  KNPKMaterialKey =
+    Position::zobMaterial[WHITE][KNIGHT][1] ^
+    Position::zobMaterial[WHITE][PAWN][1];
+  KKNPMaterialKey =
+    Position::zobMaterial[BLACK][KNIGHT][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+  KPKPMaterialKey =
+    Position::zobMaterial[WHITE][PAWN][1] ^
+    Position::zobMaterial[BLACK][PAWN][1];
+}
+
+
+/// Constructor for the MaterialInfoTable class.
+
+MaterialInfoTable::MaterialInfoTable(unsigned numOfEntries) {
+  size = numOfEntries;
+  entries = new MaterialInfo[size];
+  if(entries == NULL) {
+    std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo))
+              << " bytes for material hash table." << std::endl;
+    exit(EXIT_FAILURE);
+  }
+  this->clear();
+}
+
+
+/// Destructor for the MaterialInfoTable class.
+
+MaterialInfoTable::~MaterialInfoTable() {
+  delete [] entries;
+}
+
+
+/// MaterialInfoTable::clear() clears a material hash table by setting
+/// all entries to 0.
+
+void MaterialInfoTable::clear() {
+  memset(entries, 0, size * sizeof(MaterialInfo));
+}
+
+
+/// MaterialInfoTable::get_material_info() takes a position object as input,
+/// computes or looks up a MaterialInfo object, and returns a pointer to it.
+/// If the material configuration is not already present in the table, it
+/// is stored there, so we don't have to recompute everything when the 
+/// same material configuration occurs again.
+
+MaterialInfo *MaterialInfoTable::get_material_info(const Position &pos) {
+  Key key = pos.get_material_key();
+  int index = key & (size - 1);
+  MaterialInfo *mi = entries + index;
+
+  // If mi->key matches the position's material hash key, it means that we 
+  // have analysed this material configuration before, and we can simply
+  // return the information we found the last time instead of recomputing it:
+  if(mi->key == key)
+    return mi;
+
+  // Clear the MaterialInfo object, and set its key:
+  mi->clear();
+  mi->key = key;
+
+  // A special case before looking for a specialized evaluation function:
+  // KNN vs K is a draw:
+  if(key == KNNKMaterialKey || key == KKNNMaterialKey) {
+    mi->factor[WHITE] = mi->factor[BLACK] = 0;
+    return mi;
+  }
+
+  // Let's look if we have a specialized evaluation function for this
+  // particular material configuration:
+  if(key == KPKMaterialKey) {
+    mi->evaluationFunction = &EvaluateKPK;
+    return mi;
+  }
+  else if(key == KKPMaterialKey) {
+    mi->evaluationFunction = &EvaluateKKP;
+    return mi;
+  }
+  else if(key == KBNKMaterialKey) {
+    mi->evaluationFunction = &EvaluateKBNK;
+    return mi;
+  }
+  else if(key == KKBNMaterialKey) {
+    mi->evaluationFunction = &EvaluateKKBN;
+    return mi;
+  }
+  else if(key == KRKPMaterialKey) {
+    mi->evaluationFunction = &EvaluateKRKP;
+    return mi;
+  }
+  else if(key == KPKRMaterialKey) {
+    mi->evaluationFunction = &EvaluateKPKR;
+    return mi;
+  }
+  else if(key == KRKBMaterialKey) {
+    mi->evaluationFunction = &EvaluateKRKB;
+    return mi;
+  }
+  else if(key == KBKRMaterialKey) {
+    mi->evaluationFunction = &EvaluateKBKR;
+    return mi;
+  }
+  else if(key == KRKNMaterialKey) {
+    mi->evaluationFunction = &EvaluateKRKN;
+    return mi;
+  }
+  else if(key == KNKRMaterialKey) {
+    mi->evaluationFunction = &EvaluateKNKR;
+    return mi;
+  }
+  else if(key == KQKRMaterialKey) {
+    mi->evaluationFunction = &EvaluateKQKR;
+    return mi;
+  }
+  else if(key == KRKQMaterialKey) {
+    mi->evaluationFunction = &EvaluateKRKQ;
+    return mi;
+  }
+  else if(pos.non_pawn_material(BLACK) == Value(0) &&
+          pos.pawn_count(BLACK) == 0 &&
+          pos.non_pawn_material(WHITE) >= RookValueEndgame) {
+    mi->evaluationFunction = &EvaluateKXK;
+    return mi;
+  }
+  else if(pos.non_pawn_material(WHITE) == Value(0) &&
+          pos.pawn_count(WHITE) == 0 &&
+          pos.non_pawn_material(BLACK) >= RookValueEndgame) {
+    mi->evaluationFunction = &EvaluateKKX;
+    return mi;
+  }
+
+  // OK, we didn't find any special evaluation function for the current
+  // material configuration.  Is there a suitable scaling function?
+  //
+  // The code below is rather messy, and it could easily get worse later,
+  // if we decide to add more special cases.  We face problems when there
+  // are several conflicting applicable scaling functions and we need to
+  // decide which one to use.
+
+  if(key == KRPKRMaterialKey) {
+    mi->scalingFunction[WHITE] = &ScaleKRPKR;
+    return mi;
+  }
+  if(key == KRKRPMaterialKey) {
+    mi->scalingFunction[BLACK] = &ScaleKRKRP;
+    return mi;
+  }
+  if(key == KRPPKRPMaterialKey) {
+    mi->scalingFunction[WHITE] = &ScaleKRPPKRP;
+    return mi;
+  }
+  else if(key == KRPKRPPMaterialKey) {
+    mi->scalingFunction[BLACK] = &ScaleKRPKRPP;
+    return mi;
+  }
+  if(key == KBPKBMaterialKey) {
+    mi->scalingFunction[WHITE] = &ScaleKBPKB;
+    return mi;
+  }
+  if(key == KBKBPMaterialKey) {
+    mi->scalingFunction[BLACK] = &ScaleKBKBP;
+    return mi;
+  }
+  if(key == KBPKNMaterialKey) {
+    mi->scalingFunction[WHITE] = &ScaleKBPKN;
+    return mi;
+  }
+  if(key == KNKBPMaterialKey) {
+    mi->scalingFunction[BLACK] = &ScaleKNKBP;
+    return mi;
+  }
+  if(key == KNPKMaterialKey) {
+    mi->scalingFunction[WHITE] = &ScaleKNPK;
+    return mi;
+  }
+  if(key == KKNPMaterialKey) {
+    mi->scalingFunction[BLACK] = &ScaleKKNP;
+    return mi;
+  }
+
+  if(pos.non_pawn_material(WHITE) == BishopValueMidgame &&
+     pos.bishop_count(WHITE) == 1 && pos.pawn_count(WHITE) >= 1)
+    mi->scalingFunction[WHITE] = &ScaleKBPK;
+  if(pos.non_pawn_material(BLACK) == BishopValueMidgame &&
+     pos.bishop_count(BLACK) == 1 && pos.pawn_count(BLACK) >= 1)
+    mi->scalingFunction[BLACK] = &ScaleKKBP;
+
+  if(pos.pawn_count(WHITE) == 0 &&
+     pos.non_pawn_material(WHITE) == QueenValueMidgame &&
+     pos.queen_count(WHITE) == 1 &&
+     pos.rook_count(BLACK) == 1 && pos.pawn_count(BLACK) >= 1)
+    mi->scalingFunction[WHITE] = &ScaleKQKRP;
+  else if(pos.pawn_count(BLACK) == 0 &&
+          pos.non_pawn_material(BLACK) == QueenValueMidgame &&
+          pos.queen_count(BLACK) == 1 &&
+          pos.rook_count(WHITE) == 1 && pos.pawn_count(WHITE) >= 1)
+    mi->scalingFunction[BLACK] = &ScaleKRPKQ;
+
+  if(pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0)) {
+    if(pos.pawn_count(BLACK) == 0) {
+      assert(pos.pawn_count(WHITE) >= 2);
+      mi->scalingFunction[WHITE] = &ScaleKPsK;
+    }
+    else if(pos.pawn_count(WHITE) == 0) {
+      assert(pos.pawn_count(BLACK) >= 2);
+      mi->scalingFunction[BLACK] = &ScaleKKPs;
+    }
+    else if(pos.pawn_count(WHITE) == 1 && pos.pawn_count(BLACK) == 1) {
+      mi->scalingFunction[WHITE] = &ScaleKPKPw;
+      mi->scalingFunction[BLACK] = &ScaleKPKPb;
+    }
+  }
+
+  // Evaluate the material balance.
+  
+  Color c;
+  int sign;
+  Value egValue = Value(0), mgValue = Value(0);
+  
+  for(c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign) {
+
+    // No pawns makes it difficult to win, even with a material advantage:
+    if(pos.pawn_count(c) == 0 &&
+       pos.non_pawn_material(c) - pos.non_pawn_material(opposite_color(c))
+       <= BishopValueMidgame) {
+      if(pos.non_pawn_material(c) == pos.non_pawn_material(opposite_color(c)))
+        mi->factor[c] = 0;
+      else if(pos.non_pawn_material(c) < RookValueMidgame)
+        mi->factor[c] = 0;
+      else {
+        switch(pos.bishop_count(c)) {
+        case 2:
+          mi->factor[c] = 32; break;
+        case 1:
+          mi->factor[c] = 12; break;
+        case 0:
+          mi->factor[c] = 6; break;
+        }
+      }
+    }
+    
+    // Bishop pair:
+    if(pos.bishop_count(c) >= 2) {
+      mgValue += sign * BishopPairMidgameBonus;
+      egValue += sign * BishopPairEndgameBonus;
+    }
+
+    // Knights are stronger when there are many pawns on the board.  The 
+    // formula is taken from Larry Kaufman's paper "The Evaluation of Material
+    // Imbalances in Chess": 
+    // http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm
+    mgValue += sign * Value(pos.knight_count(c)*(pos.pawn_count(c)-5)*16);
+    egValue += sign * Value(pos.knight_count(c)*(pos.pawn_count(c)-5)*16);
+
+    // Redundancy of major pieces, again based on Kaufman's paper:
+    if(pos.rook_count(c) >= 1) {
+      Value v = Value((pos.rook_count(c) - 1) * 32 + pos.queen_count(c) * 16);
+      mgValue -= sign * v;
+      egValue -= sign * v;
+    }
+      
+  }
+
+  mi->mgValue = int16_t(mgValue);
+  mi->egValue = int16_t(egValue);
+
+  return mi;
+}
diff --git a/src/material.h b/src/material.h
new file mode 100644 (file)
index 0000000..7d5c3ce
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(MATERIAL_H_INCLUDED)
+#define MATERIAL_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "endgame.h"
+#include "position.h"
+#include "scale.h"
+
+
+////
+//// Types
+////
+
+/// MaterialInfo is a class which 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" for black and white.
+///
+/// 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.
+
+class MaterialInfo {
+
+  friend class MaterialInfoTable;
+
+public:
+  Value mg_value() const;
+  Value eg_value() const;
+  ScaleFactor scale_factor(const Position &pos, Color c) const;
+  bool specialized_eval_exists() const;
+  Value evaluate(const Position &pos) const;
+
+  static void init();
+
+private:
+  void clear();
+  
+  Key key;
+  int16_t mgValue;
+  int16_t egValue;
+  uint8_t factor[2];
+  EndgameEvaluationFunction *evaluationFunction;
+  ScalingFunction *scalingFunction[2];
+};
+
+
+/// The MaterialInfoTable class represents a pawn hash table.  It is basically
+/// just an array of MaterialInfo objects and a few methods for accessing these
+/// objects.  The most important method is get_material_info, which looks up a
+/// position in the table and returns a pointer to a MaterialInfo object.
+
+class MaterialInfoTable {
+
+public:
+  MaterialInfoTable(unsigned numOfEntries);
+  ~MaterialInfoTable();
+  void clear();
+  MaterialInfo *get_material_info(const Position &pos);
+
+private:
+  unsigned size;
+  MaterialInfo *entries;
+};
+
+
+////
+//// Inline functions
+////
+
+/// MaterialInfo::mg_value and MaterialInfo::eg_value simply returns the
+/// material balance evaluation for the middle game and the endgame.
+
+inline Value MaterialInfo::mg_value() const {
+  return Value(mgValue);
+}
+
+inline Value MaterialInfo::eg_value() const {
+  return Value(egValue);
+}
+
+
+/// MaterialInfo::clear() resets a MaterialInfo object to an empty state,
+/// with all slots at their default values.
+
+inline void MaterialInfo::clear() {
+  mgValue = egValue = 0;
+  factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
+  evaluationFunction = NULL;
+  scalingFunction[WHITE] = scalingFunction[BLACK] = NULL;
+}
+
+
+/// MaterialInfo::scale_factor takes a position and a color as input, and
+/// returns a scale factor for the given color.  We have to provide the
+/// position in addition to the color, because the scale factor need not
+/// 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
+/// which checks for draws with rook pawns and wrong-colored bishops.
+
+inline ScaleFactor MaterialInfo::scale_factor(const Position &pos, Color c)
+  const {
+  if(scalingFunction[c] != NULL) {
+    ScaleFactor sf = scalingFunction[c]->apply(pos);
+    if(sf != SCALE_FACTOR_NONE)
+      return sf;
+  }
+  return ScaleFactor(factor[c]);
+}
+
+
+/// MaterialInfo::specialized_eval_exists decides whether there is a
+/// specialized evaluation function for the current material configuration,
+/// or if the normal evaluation function should be used.
+
+inline bool MaterialInfo::specialized_eval_exists() const {
+  return evaluationFunction != NULL;
+}
+
+
+/// MaterialInfo::evaluate applies a specialized evaluation function to a
+/// given position object.  It should only be called when
+/// this->specialized_eval_exists() returns 'true'.
+
+inline Value MaterialInfo::evaluate(const Position &pos) const {
+  return evaluationFunction->apply(pos);
+}
+
+#endif // !defined(MATERIAL_H_INCLUDED)
diff --git a/src/mersenne.cpp b/src/mersenne.cpp
new file mode 100644 (file)
index 0000000..2213e4a
--- /dev/null
@@ -0,0 +1,148 @@
+/* 
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Before using, initialize the state by using init_genrand(seed)  
+   or init_by_array(init_key, key_length).
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.                          
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include "types.h"
+
+/* Period parameters */  
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL   /* constant vector a */
+#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
+
+static unsigned long mt[N]; /* the array for the state vector  */
+static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
+
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s)
+{
+    mt[0]= s & 0xffffffffUL;
+    for (mti=1; mti<N; mti++) {
+        mt[mti] = 
+            (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 
+        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+        /* In the previous versions, MSBs of the seed affect   */
+        /* only MSBs of the array mt[].                        */
+        /* 2002/01/09 modified by Makoto Matsumoto             */
+        mt[mti] &= 0xffffffffUL;
+        /* for >32 bit machines */
+    }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[], int key_length)
+{
+    int i, j, k;
+    init_genrand(19650218UL);
+    i=1; j=0;
+    k = (N>key_length ? N : key_length);
+    for (; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+          + init_key[j] + j; /* non linear */
+        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++; j++;
+        if (i>=N) { mt[0] = mt[N-1]; i=1; }
+        if (j>=key_length) j=0;
+    }
+    for (k=N-1; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
+          - i; /* non linear */
+        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++;
+        if (i>=N) { mt[0] = mt[N-1]; i=1; }
+    }
+
+    mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ 
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+uint32_t genrand_int32(void) {
+  unsigned long y;
+  static unsigned long mag01[2]={0x0UL, MATRIX_A};
+  /* mag01[x] = x * MATRIX_A  for x=0,1 */
+
+  if (mti >= N) { /* generate N words at one time */
+    int kk;
+
+    if (mti == N+1)   /* if init_genrand() has not been called, */
+      init_genrand(5489UL); /* a default initial seed is used */
+
+    for (kk=0;kk<N-M;kk++) {
+      y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+      mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+    }
+    for (;kk<N-1;kk++) {
+      y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+      mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+    }
+    y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
+    mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+    mti = 0;
+  }
+  
+  y = mt[mti++];
+
+  /* Tempering */
+  y ^= (y >> 11);
+  y ^= (y << 7) & 0x9d2c5680UL;
+  y ^= (y << 15) & 0xefc60000UL;
+  y ^= (y >> 18);
+
+  return y;
+}
+
+uint64_t genrand_int64(void) {
+  uint64_t x, y;
+
+  x = genrand_int32(); y = genrand_int32();
+  return (x<<32)|y;
+}
+
+void init_mersenne(void) {
+  unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
+  init_by_array(init, length);
+}
diff --git a/src/mersenne.h b/src/mersenne.h
new file mode 100644 (file)
index 0000000..3c1c226
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(MERSENNE_H_INCLUDED)
+#define MERSENNE_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include "types.h"
+
+
+////
+//// Prototypes
+////
+
+extern uint32_t genrand_int32(void);
+extern uint64_t genrand_int64(void);
+extern void init_mersenne(void);
+
+
+#endif // !defined(MERSENNE_H_INCLUDED)
diff --git a/src/misc.cpp b/src/misc.cpp
new file mode 100644 (file)
index 0000000..a2dc53a
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#if !defined(_MSC_VER)
+
+#  include <sys/time.h>
+#  include <sys/types.h>
+#  include <unistd.h>
+
+#else
+
+#  include <windows.h>
+#  include <time.h>
+#  include "dos.h"
+int gettimeofday(struct timeval * tp, struct timezone * tzp);
+
+#endif
+
+#include <cstdio>
+#include <iomanip>
+#include <sstream>
+
+#include "misc.h"
+
+
+//// 
+//// Functions
+////
+
+/// engine_name() returns the full name of the current Glaurung version.
+/// This will be either "Glaurung YYMMDD" (where YYMMDD is the date when the
+/// program was compiled) or "Glaurung <version number>", depending on whether
+/// the constant EngineVersion (defined in misc.h) is empty.
+
+const std::string engine_name() {
+  if(EngineVersion == "") {
+    static const char monthNames[12][4] = {
+      "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
+    };
+    const char *dateString = __DATE__;
+    std::stringstream s;
+    int month = 0, day = 0;
+    
+    for(int i = 0; i < 12; i++)
+      if(strncmp(dateString, monthNames[i], 3) == 0)
+        month = i + 1;
+    day = atoi(dateString+4);
+    
+    s << "Glaurung " << (dateString+9) << std::setfill('0') << std::setw(2)
+      << month << std::setfill('0') << std::setw(2) << day;
+    
+    return s.str();
+  }
+  else
+    return "Glaurung " + EngineVersion;
+}
+
+
+/// get_system_time() returns the current system time, measured in
+/// milliseconds.
+
+int get_system_time() {
+  struct timeval t;
+  gettimeofday(&t, NULL);
+  return t.tv_sec*1000 + t.tv_usec/1000; 
+}
+
+
+/// cpu_count() tries to detect the number of CPU cores.
+
+#if !defined(_MSC_VER)
+
+#  if defined(_SC_NPROCESSORS_ONLN)
+int cpu_count() {
+  return Min(sysconf(_SC_NPROCESSORS_ONLN), 8);
+}
+#  else
+int cpu_count() {
+  return 1;
+}
+#  endif
+
+#else
+
+int cpu_count() {
+  SYSTEM_INFO s;
+  GetSystemInfo(&s);
+  return Min(s.dwNumberOfProcessors, 8);
+}
+
+#endif
+
+
+/*
+  From Beowulf, from Olithink
+*/
+#ifndef _WIN32
+/* Non-windows version */
+int Bioskey()
+{
+  fd_set          readfds;
+  struct timeval  timeout;
+  
+  FD_ZERO(&readfds);
+  FD_SET(fileno(stdin), &readfds);
+  /* Set to timeout immediately */
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 0;
+  select(16, &readfds, 0, 0, &timeout);
+  
+  return (FD_ISSET(fileno(stdin), &readfds));
+}
+
+#else
+/* Windows-version */
+#include <windows.h>
+#include <conio.h>
+int Bioskey()
+{
+    static int      init = 0,
+                    pipe;
+    static HANDLE   inh;
+    DWORD           dw;
+    /* If we're running under XBoard then we can't use _kbhit() as the input
+     * commands are sent to us directly over the internal pipe */
+
+#if defined(FILE_CNT)
+    if (stdin->_cnt > 0)
+        return stdin->_cnt;
+#endif
+    if (!init) {
+        init = 1;
+        inh = GetStdHandle(STD_INPUT_HANDLE);
+        pipe = !GetConsoleMode(inh, &dw);
+        if (!pipe) {
+            SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
+            FlushConsoleInputBuffer(inh);
+        }
+    }
+    if (pipe) {
+        if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL))
+            return 1;
+        return dw;
+    } else {
+        GetNumberOfConsoleInputEvents(inh, &dw);
+        return dw <= 1 ? 0 : dw;
+    }
+}
+#endif
diff --git a/src/misc.h b/src/misc.h
new file mode 100644 (file)
index 0000000..d629045
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(MISC_H_INCLUDED)
+#define MISC_H_INCLUDED
+
+
+////
+//// Includes
+////
+
+#include <string>
+
+
+////
+//// Constants
+////
+
+
+/// Version number.  If this is left empty, the current date (in the format
+/// YYMMDD) is used as a version number.
+
+const std::string EngineVersion = "2.1";
+
+
+////
+//// Macros
+////
+
+#define Min(x, y) (((x) < (y))? (x) : (y))
+#define Max(x, y) (((x) < (y))? (y) : (x))
+
+
+////
+//// Prototypes
+////
+
+extern const std::string engine_name();
+extern int get_system_time();
+extern int cpu_count();
+extern int Bioskey();
+
+
+#endif // !defined(MISC_H_INCLUDED)
diff --git a/src/move.cpp b/src/move.cpp
new file mode 100644 (file)
index 0000000..2de102d
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+
+#include "move.h"
+#include "piece.h"
+#include "position.h"
+#include "ucioption.h"
+
+
+////
+//// Functions
+////
+
+/// move_from_string() takes a position and a string as input, and attempts to
+/// convert the string to a move, using simple coordinate notation (g1f3,
+/// a7a8q, etc.).  In order to correctly parse en passant captures and castling
+/// moves, we need the position.  This function is not robust, and expects that
+/// the input move is legal and correctly formatted.
+
+Move move_from_string(const Position &pos, const std::string &str) {
+  Square from, to;
+  Piece piece;
+  Color us = pos.side_to_move();
+
+  if(str.length() < 4) return MOVE_NONE;
+
+  // Read the from and to squares:
+  from = square_from_string(str.substr(0, 2));
+  to = square_from_string(str.substr(2, 4));
+
+  // Find the moving piece:
+  piece = pos.piece_on(from);
+
+  // If the string has more than 4 characters, try to interpret the 5th
+  // character as a promotion:
+  if(type_of_piece(piece) == PAWN && str.length() >= 5) {
+    switch(str[4]) {
+    case 'n': case 'N': 
+      return make_promotion_move(from, to, KNIGHT);
+    case 'b': case 'B':
+      return make_promotion_move(from, to, BISHOP);
+    case 'r': case 'R':
+      return make_promotion_move(from, to, ROOK);
+    case 'q': case 'Q':
+      return make_promotion_move(from, to, QUEEN);
+    }
+  }
+
+  if(piece == king_of_color(us)) {
+    // Is this a castling move?  A king move is assumed to be a castling
+    // move if the destination square is occupied by a friendly rook, or
+    // if the distance between the source and destination squares is more
+    // than 1.
+    if(pos.piece_on(to) == rook_of_color(us))
+      return make_castle_move(from, to);
+    else if(square_distance(from, to) > 1) {
+      // This is a castling move, but we have to translate it to the
+      // internal "king captures rook" representation.
+      SquareDelta delta = (to > from)? DELTA_E : DELTA_W;
+      Square s;
+      for(s = from + delta;
+          pawn_rank(us, s) == RANK_1 && pos.piece_on(s) != rook_of_color(us);
+          s += delta);
+      if(pawn_rank(us, s) == RANK_1 && pos.piece_on(s) == rook_of_color(us))
+        return make_castle_move(from, s);
+    }
+  }
+  else if(piece == pawn_of_color(us)) {
+    // En passant move?  We assume that a pawn move is an en passant move
+    // without further testing if the destination square is epSquare.
+    if(to == pos.ep_square())
+      return make_ep_move(from, to);
+  }
+
+  return make_move(from, to);
+}
+
+
+/// move_to_string() converts a move to a string in coordinate notation
+/// (g1f3, a7a8q, etc.).  The only special case is castling moves, where we
+/// print in the e1g1 notation in normal chess mode, and in e1h1 notation in
+/// Chess960 mode.
+
+const std::string move_to_string(Move move) {
+  std::string str;
+
+  if(move == MOVE_NONE)
+    str = "(none)";
+  else if(move == MOVE_NULL)
+    str = "0000";
+  else {
+    if(!Chess960) {
+      if(move_from(move) == SQ_E1 && move_is_short_castle(move)) {
+        str = "e1g1"; return str;
+      }
+      else if(move_from(move) == SQ_E1 && move_is_long_castle(move)) {
+        str = "e1c1"; return str;
+      }
+      if(move_from(move) == SQ_E8 && move_is_short_castle(move)) {
+        str = "e8g8"; return str;
+      }
+      else if(move_from(move) == SQ_E8 && move_is_long_castle(move)) {
+        str = "e8c8"; return str;
+      }
+    }
+    str = square_to_string(move_from(move)) + square_to_string(move_to(move));
+    if(move_promotion(move))
+      str += piece_type_to_char(move_promotion(move), false);
+  }
+  return str;
+}
+
+
+/// Overload the << operator, to make it easier to print moves.
+
+std::ostream &operator << (std::ostream &os, Move m) {
+  return os << move_to_string(m);
+}
+
+
+/// move_is_ok(), for debugging.
+
+bool move_is_ok(Move m) {
+  return square_is_ok(move_from(m)) && square_is_ok(move_to(m));
+}
diff --git a/src/move.h b/src/move.h
new file mode 100644 (file)
index 0000000..65fcc25
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(MOVE_H_INCLUDED)
+#define MOVE_H_INCLUDED
+
+////
+//// Includes
+////
+
+#include <iostream>
+
+#include "misc.h"
+#include "piece.h"
+#include "square.h"
+
+
+////
+//// Types
+////
+
+class Position;
+
+enum Move {
+  MOVE_NONE = 0,
+  MOVE_NULL = 65, 
+  MOVE_MAX = 0xFFFFFF
+};
+
+
+struct MoveStack {
+  Move move;
+  int score;
+};
+
+
+////
+//// Inline functions
+////
+
+inline Square move_from(Move m) {
+  return Square((int(m) >> 6) & 077);
+}
+
+inline Square move_to(Move m) {
+  return Square(m & 077);
+}
+
+inline PieceType move_promotion(Move m) {
+  return PieceType((int(m) >> 12) & 7);
+}
+
+inline bool move_is_ep(Move m) {
+  return bool((int(m) >> 15) & 1);
+}
+
+inline bool move_is_castle(Move m) {
+  return bool((int(m) >> 16) & 1);
+}
+
+inline bool move_is_short_castle(Move m) {
+  return move_is_castle(m) && (move_to(m) > move_from(m));
+}
+
+inline bool move_is_long_castle(Move m) {
+  return move_is_castle(m) && (move_to(m) < move_from(m));
+}
+
+inline Move make_promotion_move(Square from, Square to, PieceType promotion) {
+  return Move(int(to) | (int(from) << 6) | (int(promotion) << 12));
+}
+
+inline Move make_move(Square from, Square to) {
+  return Move(int(to) | (int(from) << 6));
+}
+
+inline Move make_castle_move(Square from, Square to) {
+  return Move(int(to) | (int(from) << 6) | (1 << 16));
+}
+
+inline Move make_ep_move(Square from, Square to) {
+  return Move(int(to) | (int(from) << 6) | (1 << 15));
+}
+
+
+////
+//// Prototypes
+////
+
+extern std::ostream &operator << (std::ostream &os, Move m);
+extern Move move_from_string(const Position &pos, const std::string &str);
+extern const std::string move_to_string(Move m);
+extern bool move_is_ok(Move m);
+
+
+#endif // !defined(MOVE_H_INCLUDED)
diff --git a/src/movegen.cpp b/src/movegen.cpp
new file mode 100644 (file)
index 0000000..ecdcd8f
--- /dev/null
@@ -0,0 +1,1238 @@
+/*
+  Glaurung, a UCI chess playing engine.
+  Copyright (C) 2004-2008 Tord Romstad
+
+  Glaurung 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.
+  
+  Glaurung is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include <cassert>
+
+#include "movegen.h"
+
+
+////
+//// Local definitions
+////
+
+namespace {
+  
+  int generate_white_pawn_captures(const Position &pos, MoveStack *mlist);
+  int generate_black_pawn_captures(const Position &pos, MoveStack *mlist);
+  int generate_white_pawn_noncaptures(const Position &pos, MoveStack *mlist);
+  int generate_black_pawn_noncaptures(const Position &pos, MoveStack *mlist);
+  int generate_knight_moves(const Position &pos, MoveStack *mlist, 
+                            Color side, Bitboard target);
+  int generate_bishop_moves(const Position &pos, MoveStack *mlist, 
+                            Color side, Bitboard target);
+  int generate_rook_moves(const Position &pos, MoveStack *mlist, 
+                          Color side, Bitboard target);
+  int generate_queen_moves(const Position &pos, MoveStack *mlist, 
+                           Color side, Bitboard target);
+  int generate_king_moves(const Position &pos, MoveStack *mlist, 
+                          Square from, Bitboard target);
+  int generate_castle_moves(const Position &pos, MoveStack *mlist, Color us);
+
+}
+
+
+////
+//// Functions
+////
+
+
+/// generate_captures generates() all pseudo-legal captures and queen
+/// promotions.  The return value is the number of moves generated.
+
+int generate_captures(const Position &pos, MoveStack *mlist) {
+  Color us = pos.side_to_move();
+  Bitboard target = pos.pieces_of_color(opposite_color(us));
+  int n = 0;
+
+  assert(pos.is_ok());
+  assert(!pos.is_check());
+
+  if(us == WHITE)
+    n += generate_white_pawn_captures(pos, mlist);
+  else
+    n += generate_black_pawn_captures(pos, mlist);
+  n += generate_knight_moves(pos, mlist+n, us, target);
+  n += generate_bishop_moves(pos, mlist+n, us, target);
+  n += generate_rook_moves(pos, mlist+n, us, target);
+  n += generate_queen_moves(pos, mlist+n, us, target);
+  n += generate_king_moves(pos, mlist+n, pos.king_square(us), target);
+
+  return n;
+}
+
+
+/// generate_noncaptures() generates all pseudo-legal non-captures and 
+/// underpromotions.  The return value is the number of moves generated.
+
+int generate_noncaptures(const Position &pos, MoveStack *mlist) {
+  Color us = pos.side_to_move();
+  Bitboard target = pos.empty_squares();
+  int n = 0;
+
+  assert(pos.is_ok());
+  assert(!pos.is_check());
+
+  if(us == WHITE)
+    n += generate_white_pawn_noncaptures(pos, mlist);
+  else
+    n += generate_black_pawn_noncaptures(pos, mlist);
+  n += generate_knight_moves(pos, mlist+n, us, target);
+  n += generate_bishop_moves(pos, mlist+n, us, target);
+  n += generate_rook_moves(pos, mlist+n, us, target);
+  n += generate_queen_moves(pos, mlist+n, us, target);
+  n += generate_king_moves(pos, mlist+n, pos.king_square(us), target);
+  n += generate_castle_moves(pos, mlist+n, us);
+
+  return n;
+}
+
+
+/// generate_checks() generates all pseudo-legal non-capturing, non-promoting
+/// checks, except castling moves (will add this later).  It returns the
+/// number of generated moves.  
+
+int generate_checks(const Position &pos, MoveStack *mlist, Bitboard dc) {
+  Color us, them;
+  Square ksq, from, to;
+  Bitboard empty, checkSqs, b1, b2, b3;
+  int n = 0;
+
+  assert(pos.is_ok());
+  assert(!pos.is_check());
+
+  us = pos.side_to_move();
+  them = opposite_color(us);
+
+  ksq = pos.king_square(them);
+  assert(pos.piece_on(ksq) == king_of_color(them));
+
+  dc = pos.discovered_check_candidates(us);
+  empty = pos.empty_squares();
+  
+  // Pawn moves.  This is somewhat messy, and we use separate code for white
+  // and black, because we can't shift by negative numbers in C/C++.  :-(
+
+  if(us == WHITE) {
+    // Pawn moves 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.
+
+    // Find all friendly pawns not on the enemy king's file:
+    b1 = pos.pawns(us) & ~file_bb(ksq);
+
+    // Discovered checks, single pawn pushes:
+    b2 = b3 = ((b1 & dc) << 8) & ~Rank8BB & empty;
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_N, to);
+    }
+
+    // Discovered checks, double pawn pushes:
+    b3 = ((b2 & Rank3BB) << 8) & empty;
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_N - DELTA_N, to);
+    }
+
+    // Direct checks.  These are possible only for pawns on neighboring files
+    // of the enemy king:
+
+    b1 &= (~dc & neighboring_files_bb(ksq));
+
+    // Direct checks, single pawn pushes:
+    b2 = (b1 << 8) & empty;
+    b3 = b2 & pos.black_pawn_attacks(ksq);
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_N, to);
+    }
+
+    // Direct checks, double pawn pushes:
+    b3 = ((b2 & Rank3BB) << 8) & empty & pos.black_pawn_attacks(ksq);
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_N - DELTA_N, to);
+    }
+  }
+  else { // (us == BLACK)
+
+    // Pawn moves 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.
+
+    // Find all friendly pawns not on the enemy king's file:
+    b1 = pos.pawns(us) & ~file_bb(ksq);
+
+    // Discovered checks, single pawn pushes:
+    b2 = b3 = ((b1 & dc) >> 8) & ~Rank1BB & empty;
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_S, to);
+    }
+
+    // Discovered checks, double pawn pushes:
+    b3 = ((b2 & Rank6BB) >> 8) & empty;
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_S - DELTA_S, to);
+    }
+
+    // Direct checks.  These are possible only for pawns on neighboring files
+    // of the enemy king:
+
+    b1 &= (~dc & neighboring_files_bb(ksq));
+
+    // Direct checks, single pawn pushes:
+    b2 = (b1 >> 8) & empty;
+    b3 = b2 & pos.white_pawn_attacks(ksq);
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_S, to);
+    }
+
+    // Direct checks, double pawn pushes:
+    b3 = ((b2 & Rank6BB) >> 8) & empty & pos.black_pawn_attacks(ksq);
+    while(b3) {
+      to = pop_1st_bit(&b3);
+      mlist[n++].move = make_move(to - DELTA_S - DELTA_S, to);
+    }
+  }
+
+  // Knight moves
+  b1 = pos.knights(us);
+  if(b1) {
+    // Discovered knight checks:
+    b2 = b1 & dc;
+    while(b2) {
+      from = pop_1st_bit(&b2);
+      b3 = pos.knight_attacks(from) & empty;
+      while(b3) {
+        to = pop_1st_bit(&b3);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    
+    // Direct knight checks:
+    b2 = b1 & ~dc;
+    checkSqs = pos.knight_attacks(ksq) & empty;
+    while(b2) {
+      from = pop_1st_bit(&b2);
+      b3 = pos.knight_attacks(from) & checkSqs;
+      while(b3) {
+        to = pop_1st_bit(&b3);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+  }
+
+  // Bishop moves
+  b1 = pos.bishops(us);
+  if(b1) {
+    // Discovered bishop checks:
+    b2 = b1 & dc;
+    while(b2) {
+      from = pop_1st_bit(&b2);
+      b3 = pos.bishop_attacks(from) & empty;
+      while(b3) {
+        to = pop_1st_bit(&b3);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    
+    // Direct bishop checks:
+    b2 = b1 & ~dc;
+    checkSqs = pos.bishop_attacks(ksq) & empty;
+    while(b2) {
+      from = pop_1st_bit(&b2);
+      b3 = pos.bishop_attacks(from) & checkSqs;
+      while(b3) {
+        to = pop_1st_bit(&b3);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+  }
+
+  // Rook moves
+  b1 = pos.rooks(us);
+  if(b1) {
+    // Discovered rook checks:
+    b2 = b1 & dc;
+    while(b2) {
+      from = pop_1st_bit(&b2);
+      b3 = pos.rook_attacks(from) & empty;
+      while(b3) {
+        to = pop_1st_bit(&b3);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    
+    // Direct rook checks:
+    b2 = b1 & ~dc;
+    checkSqs = pos.rook_attacks(ksq) & empty;
+    while(b2) {
+      from = pop_1st_bit(&b2);
+      b3 = pos.rook_attacks(from) & checkSqs;
+      while(b3) {
+        to = pop_1st_bit(&b3);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+  }
+
+  // Queen moves
+  b1 = pos.queens(us);
+  if(b1) {
+    // Discovered queen checks are impossible!
+
+    // Direct queen checks:
+    checkSqs = pos.queen_attacks(ksq) & empty;
+    while(b1) {
+      from = pop_1st_bit(&b1);
+      b2 = pos.queen_attacks(from) & checkSqs;
+      while(b2) {
+        to = pop_1st_bit(&b2);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+  }
+
+  // King moves
+  from = pos.king_square(us);
+  if(bit_is_set(dc, from)) {
+    b1 = pos.king_attacks(from) & empty & ~QueenPseudoAttacks[ksq];
+    while(b1) {
+      to = pop_1st_bit(&b1);
+      mlist[n++].move = make_move(from, to);
+    }
+  }
+
+  // TODO: Castling moves!
+  
+  return n;
+}
+
+
+/// generate_evasions() generates all check evasions when the side to move is
+/// in check.  Unlike the other move generation functions, this one generates
+/// only legal moves.  It returns the number of generated moves.  This
+/// function is very ugly, and needs cleaning up some time later.  FIXME
+
+int generate_evasions(const Position &pos, MoveStack *mlist) {
+  Color us, them;
+  Bitboard checkers = pos.checkers();
+  Bitboard pinned, b1, b2;
+  Square ksq, from, to;
+  int n = 0;
+
+  assert(pos.is_ok());
+  assert(pos.is_check());
+
+  us = pos.side_to_move();
+  them = opposite_color(us);
+
+  ksq = pos.king_square(us);
+  assert(pos.piece_on(ksq) == king_of_color(us));
+  
+  // Generate evasions for king:
+  b1 = pos.king_attacks(ksq) & ~pos.pieces_of_color(us);
+  b2 = pos.occupied_squares();
+  clear_bit(&b2, ksq);
+  while(b1) {
+    to = pop_1st_bit(&b1);
+
+    // Make sure to is not attacked by the other side.  This is a bit ugly,
+    // because we can't use Position::square_is_attacked.  Instead we use
+    // the low-level bishop_attacks_bb and rook_attacks_bb with the bitboard
+    // b2 (the occupied squares with the king removed) in order to test whether
+    // the king will remain in check on the destination square.
+    if(((pos.pawn_attacks(us, to) & pos.pawns(them)) == EmptyBoardBB) &&
+       ((pos.knight_attacks(to) & pos.knights(them)) == EmptyBoardBB) &&
+       ((pos.king_attacks(to) & pos.kings(them)) == EmptyBoardBB) &&
+       ((bishop_attacks_bb(to, b2) & pos.bishops_and_queens(them))
+        == EmptyBoardBB) &&
+       ((rook_attacks_bb(to, b2) & pos.rooks_and_queens(them)) == EmptyBoardBB))
+      mlist[n++].move = make_move(ksq, to);
+  }
+
+
+  // Generate evasions for other pieces only if not double check.  We use a
+  // simple bit twiddling hack here rather than calling count_1s in order to
+  // save some time (we know that pos.checkers() has at most two nonzero bits).
+  if(!(checkers & (checkers - 1))) {
+    Square checksq = first_1(checkers);
+    assert(pos.color_of_piece_on(checksq) == them);
+
+    // Find pinned pieces:
+    pinned = pos.pinned_pieces(us);
+
+    // Generate captures of the checking piece:
+
+    // Pawn captures:
+    b1 = pos.pawn_attacks(them, checksq) & pos.pawns(us) & ~pinned;
+    while(b1) {
+      from = pop_1st_bit(&b1);
+      if(pawn_rank(us, checksq) == RANK_8) {
+        mlist[n++].move = make_promotion_move(from, checksq, QUEEN);
+        mlist[n++].move = make_promotion_move(from, checksq, ROOK);
+        mlist[n++].move = make_promotion_move(from, checksq, BISHOP);
+        mlist[n++].move = make_promotion_move(from, checksq, KNIGHT);
+      }
+      else
+        mlist[n++].move = make_move(from, checksq);
+    }
+
+    // Knight captures:
+    b1 = pos.knight_attacks(checksq) & pos.knights(us) & ~pinned;
+    while(b1) {
+      from = pop_1st_bit(&b1);
+      mlist[n++].move = make_move(from, checksq);
+    }
+
+    // Bishop and queen captures:
+    b1 = pos.bishop_attacks(checksq) & pos.bishops_and_queens(us)
+      & ~pinned;
+    while(b1) {
+      from = pop_1st_bit(&b1);
+      mlist[n++].move = make_move(from, checksq);
+    }
+
+    // Rook and queen captures:
+    b1 = pos.rook_attacks(checksq) & pos.rooks_and_queens(us)
+      & ~pinned;
+    while(b1) {
+      from = pop_1st_bit(&b1);
+      mlist[n++].move = make_move(from, checksq);
+    }
+
+    // Blocking check evasions are possible only if the checking piece is
+    // a slider:
+    if(checkers & pos.sliders()) {
+      Bitboard blockSquares = squares_between(checksq, ksq);
+      assert((pos.occupied_squares() & blockSquares) == EmptyBoardBB);
+
+      // Pawn moves.  Because a blocking evasion can never be a capture, we
+      // only generate pawn pushes.  As so often, the code for pawns is a bit
+      // ugly, and uses separate clauses for white and black pawns. :-(
+      if(us == WHITE) {
+        // Find non-pinned pawns:
+        b1 = pos.pawns(WHITE) & ~pinned;
+
+        // Single pawn pushes.  We don't have to AND with empty squares here,
+        // because the blocking squares will always be empty.
+        b2 = (b1 << 8) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          assert(pos.piece_on(to) == EMPTY);
+          if(square_rank(to) == RANK_8) {
+            mlist[n++].move = make_promotion_move(to - DELTA_N, to, QUEEN);
+            mlist[n++].move = make_promotion_move(to - DELTA_N, to, ROOK);
+            mlist[n++].move = make_promotion_move(to - DELTA_N, to, BISHOP);
+            mlist[n++].move = make_promotion_move(to - DELTA_N, to, KNIGHT);
+          }
+          else
+            mlist[n++].move = make_move(to - DELTA_N, to);
+        }
+        // Double pawn pushes.
+        b2 = (((b1 << 8) & pos.empty_squares() & Rank3BB) << 8) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          assert(pos.piece_on(to) == EMPTY);
+          assert(square_rank(to) == RANK_4);
+          mlist[n++].move = make_move(to - DELTA_N - DELTA_N, to);
+        }
+      }
+      else { // (us == BLACK)
+        // Find non-pinned pawns:
+        b1 = pos.pawns(BLACK) & ~pinned;
+
+        // Single pawn pushes.  We don't have to AND with empty squares here,
+        // because the blocking squares will always be empty.
+        b2 = (b1 >> 8) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          assert(pos.piece_on(to) == EMPTY);
+          if(square_rank(to) == RANK_1) {
+            mlist[n++].move = make_promotion_move(to - DELTA_S, to, QUEEN);
+            mlist[n++].move = make_promotion_move(to - DELTA_S, to, ROOK);
+            mlist[n++].move = make_promotion_move(to - DELTA_S, to, BISHOP);
+            mlist[n++].move = make_promotion_move(to - DELTA_S, to, KNIGHT);
+          }
+          else
+            mlist[n++].move = make_move(to - DELTA_S, to);
+        }
+        // Double pawn pushes.
+        b2 = (((b1 >> 8) & pos.empty_squares() & Rank6BB) >> 8) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          assert(pos.piece_on(to) == EMPTY);
+          assert(square_rank(to) == RANK_5);
+          mlist[n++].move = make_move(to - DELTA_S - DELTA_S, to);
+        }
+      }
+
+      // Knight moves
+      b1 = pos.knights(us) & ~pinned;
+      while(b1) {
+        from = pop_1st_bit(&b1);
+        b2 = pos.knight_attacks(from) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          mlist[n++].move = make_move(from, to);
+        }
+      }
+      
+      // Bishop moves
+      b1 = pos.bishops(us) & ~pinned;
+      while(b1) {
+        from = pop_1st_bit(&b1);
+        b2 = pos.bishop_attacks(from) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          mlist[n++].move = make_move(from, to);
+        }
+      }
+      
+      // Rook moves
+      b1 = pos.rooks(us) & ~pinned;
+      while(b1) {
+        from = pop_1st_bit(&b1);
+        b2 = pos.rook_attacks(from) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          mlist[n++].move = make_move(from, to);
+        }
+      }
+      
+      // Queen moves
+      b1 = pos.queens(us) & ~pinned;
+      while(b1) {
+        from = pop_1st_bit(&b1);
+        b2 = pos.queen_attacks(from) & blockSquares;
+        while(b2) {
+          to = pop_1st_bit(&b2);
+          mlist[n++].move = make_move(from, to);
+        }
+      }
+    }
+
+    // Finally, the ugly special case of en passant captures.  An en passant
+    // capture can only be a check evasion if the check is not a discovered
+    // check.  If pos.ep_square() is set, the last move made must have been
+    // a double pawn push.  If, furthermore, the checking piece is a pawn,
+    // an en passant check evasion may be possible.
+    if(pos.ep_square() != SQ_NONE && (checkers & pos.pawns(them))) {
+      to = pos.ep_square();
+      b1 = pos.pawn_attacks(them, to) & pos.pawns(us);
+      assert(b1 != EmptyBoardBB);
+      b1 &= ~pinned;
+      while(b1) {
+        from = pop_1st_bit(&b1);
+
+        // Before generating the move, we have to make sure it is legal.
+        // This is somewhat tricky, because the two disappearing pawns may
+        // cause new "discovered checks".  We test this by removing the
+        // two relevant bits from the occupied squares bitboard, and using
+        // the low-level bitboard functions for bishop and rook attacks.
+        b2 = pos.occupied_squares();
+        clear_bit(&b2, from);
+        clear_bit(&b2, checksq);
+        if(((bishop_attacks_bb(ksq, b2) & pos.bishops_and_queens(them))
+            == EmptyBoardBB) &&
+           ((rook_attacks_bb(ksq, b2) & pos.rooks_and_queens(them))
+            == EmptyBoardBB))
+          mlist[n++].move = make_ep_move(from, to);
+      }
+    }
+  }
+
+  return n;
+}
+
+
+/// generate_legal_moves() computes a complete list of legal moves in the
+/// current position.  This function is not very fast, and should be used
+/// only in situations where performance is unimportant.  It wouldn't be
+/// very hard to write an efficient legal move generator, but for the moment
+/// we don't need it.
+
+int generate_legal_moves(const Position &pos, MoveStack *mlist) {
+  assert(pos.is_ok());
+
+  if(pos.is_check())
+    return generate_evasions(pos, mlist);
+  else {
+    int i, n;
+    Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
+
+    // Generate pseudo-legal moves:
+    n = generate_captures(pos, mlist);
+    n += generate_noncaptures(pos, mlist + n);
+
+    // Remove illegal moves from the list:
+    for(i = 0; i < n; i++) {
+      if(!pos.move_is_legal(mlist[i].move, pinned))
+        mlist[i--].move = mlist[--n].move;
+    }
+
+    return n;
+  }
+}
+
+
+/// generate_move_if_legal() takes a position and a (not necessarily
+/// pseudo-legal) move and a pinned pieces bitboard as input, and tests
+/// whether the move is legal.  If the move is legal, the move itself is
+/// returned.  If not, the function returns MOVE_NONE.  This function must
+/// only be used when the side to move is not in check.
+
+Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) {
+  Color us, them;
+  Square from, to;
+  Piece pc;
+
+  assert(pos.is_ok());
+  assert(!pos.is_check());
+  assert(move_is_ok(m));
+
+  us = pos.side_to_move();
+  them = opposite_color(us);
+  from = move_from(m);
+  pc = pos.piece_on(from);
+
+  // If the from square is not occupied by a piece belonging to the side to
+  // move, the move is obviously not legal.
+  if(color_of_piece(pc) != us )
+    return MOVE_NONE;
+
+  to = move_to(m);
+
+  // En passant moves:
+  if(move_is_ep(m)) {
+
+    // The piece must be a pawn:
+    if(type_of_piece(pc) != PAWN)
+      return MOVE_NONE;
+
+    // The destination square must be the en passant square:
+    if(to != pos.ep_square())
+      return MOVE_NONE;
+
+    assert(pos.square_is_empty(to));
+    assert(pos.piece_on(to - pawn_push(us)) == pawn_of_color(them));
+
+    // The move is pseudo-legal.  If it is legal, return it.
+    if(pos.move_is_legal(m))
+      return m;
+    else
+      return MOVE_NONE;
+  }
+
+  // Castling moves:
+  else if(move_is_short_castle(m)) {
+
+    // The piece must be a king:
+    if(type_of_piece(pc) != KING)
+      return MOVE_NONE;
+
+    // The side to move must still have the right to castle kingside:
+    if(!pos.can_castle_kingside(us))
+      return MOVE_NONE;
+
+    assert(from == pos.king_square(us));
+    assert(to == pos.initial_kr_square(us));
+    assert(pos.piece_on(to) == rook_of_color(us));
+
+    Square g1 = relative_square(us, SQ_G1);
+    Square f1 = relative_square(us, SQ_F1);
+    Square s;
+    bool illegal = false;
+
+    for(s = Min(from, g1); s <= Max(from, g1); s++)
+      if((s != from && s != to && !pos.square_is_empty(s)) ||
+         pos.square_is_attacked(s, them))
+        illegal = true;
+    for(s = Min(to, f1); s <= Max(to, f1); s++)
+      if(s != from && s != to && !pos.square_is_empty(s))
+        illegal = true;
+
+    if(!illegal)
+      return m;
+    else
+      return MOVE_NONE;
+  }
+  else if(move_is_long_castle(m)) {
+
+    // The piece must be a king:
+    if(type_of_piece(pc) != KING)
+      return MOVE_NONE;
+
+    // The side to move must still have the right to castle kingside:
+    if(!pos.can_castle_queenside(us))
+      return MOVE_NONE;
+
+    assert(from == pos.king_square(us));
+    assert(to == pos.initial_qr_square(us));
+    assert(pos.piece_on(to) == rook_of_color(us));
+
+    Square c1 = relative_square(us, SQ_C1);
+    Square d1 = relative_square(us, SQ_D1);
+    Square s;
+    bool illegal = false;
+
+    for(s = Min(from, c1); s <= Max(from, c1); s++)
+      if((s != from && s != to && !pos.square_is_empty(s)) ||
+         pos.square_is_attacked(s, them))
+        illegal = true;
+    for(s = Min(to, d1); s <= Max(to, d1); s++)
+      if(s != from && s != to && !pos.square_is_empty(s))
+        illegal = true;
+    if(square_file(to) == FILE_B &&
+       (pos.piece_on(to + DELTA_W) == rook_of_color(them) ||
+        pos.piece_on(to + DELTA_W) == queen_of_color(them)))
+      illegal = true;
+
+    if(!illegal)
+      return m;
+    else
+      return MOVE_NONE;
+  }
+
+  // Normal moves
+  else {
+
+    // The destination square cannot be occupied by a friendly piece:
+    if(pos.color_of_piece_on(to) == us)
+      return MOVE_NONE;
+
+    // Proceed according to the type of the moving piece.
+    switch(type_of_piece(pc)) {
+
+    case PAWN:
+      // Pawn moves, as usual, are somewhat messy.  
+      if(us == WHITE) {
+        // If the destination square is on the 8th rank, the move must be a
+        // promotion.
+        if(square_rank(to) == RANK_8 && !move_promotion(m))
+          return MOVE_NONE;
+        
+        // Proceed according to the square delta between the source and
+        // destionation squares.
+        switch(to - from) {
+          
+        case DELTA_NW: case DELTA_NE:
+          // Capture.  The destination square must be occupied by an enemy piece
+          // (en passant captures was handled earlier).
+          if(pos.color_of_piece_on(to) != them)
+            return MOVE_NONE;
+          break;
+
+        case DELTA_N:
+          // Pawn push.  The destination square must be empty.
+          if(!pos.square_is_empty(to))
+            return MOVE_NONE;
+          break;
+
+        case DELTA_NN:
+          // Double pawn push.  The destination square must be on the fourth
+          // rank, and both the destination square and the square between the
+          // source and destination squares must be empty.
+          if(square_rank(to) != RANK_4 || !pos.square_is_empty(to) ||
+             !pos.square_is_empty(from + DELTA_N))
+            return MOVE_NONE;
+          break;
+          
+        default:
+          return MOVE_NONE;
+        }
+      }
+      else { // (us == BLACK)
+        // If the destination square is on the 1st rank, the move must be a
+        // promotion.
+        if(square_rank(to) == RANK_1 && !move_promotion(m))
+          return MOVE_NONE;
+        
+        // Proceed according to the square delta between the source and
+        // destionation squares.
+        switch(to - from) {
+          
+        case DELTA_SW: case DELTA_SE:
+          // Capture.  The destination square must be occupied by an enemy piece
+          // (en passant captures was handled earlier).
+          if(pos.color_of_piece_on(to) != them)
+            return MOVE_NONE;
+          break;
+          
+        case DELTA_S:
+          // Pawn push.  The destination square must be empty.
+          if(!pos.square_is_empty(to))
+            return MOVE_NONE;
+          break;
+          
+        case DELTA_SS:
+          // Double pawn push.  The destination square must be on the fifth
+          // rank, and both the destination square and the square between the
+          // source and destination squares must be empty.
+          if(square_rank(to) != RANK_5 || !pos.square_is_empty(to) ||
+             !pos.square_is_empty(from + DELTA_S))
+            return MOVE_NONE;
+          break;
+          
+        default:
+          return MOVE_NONE;
+        }
+      }
+      // The move is pseudo-legal.  Return it if it is legal.
+      if(pos.move_is_legal(m))
+        return m;
+      else
+        return MOVE_NONE;
+      break;
+
+    case KNIGHT:
+      if(pos.knight_attacks_square(from, to) && pos.move_is_legal(m) &&
+         !move_promotion(m))
+        return m;
+      else
+        return MOVE_NONE;
+      break;
+      
+    case BISHOP:
+      if(pos.bishop_attacks_square(from, to) && pos.move_is_legal(m) &&
+         !move_promotion(m))
+        return m;
+      else
+        return MOVE_NONE;
+      break;
+      
+    case ROOK:
+      if(pos.rook_attacks_square(from, to) && pos.move_is_legal(m) &&
+         !move_promotion(m))
+        return m;
+      else
+        return MOVE_NONE;
+      break;
+    
+    case QUEEN:
+      if(pos.queen_attacks_square(from, to) && pos.move_is_legal(m) &&
+         !move_promotion(m))
+        return m;
+      else
+        return MOVE_NONE;
+      break;
+
+    case KING:
+      if(pos.king_attacks_square(from, to) && pos.move_is_legal(m) &&
+         !move_promotion(m))
+        return m;
+      else
+        return MOVE_NONE;
+      break;
+
+    default:
+      assert(false);
+    }
+  }
+
+  assert(false);
+  return MOVE_NONE;
+}
+
+
+namespace {
+
+  int generate_white_pawn_captures(const Position &pos, MoveStack *mlist) {
+    Bitboard pawns = pos.pawns(WHITE);
+    Bitboard enemyPieces = pos.pieces_of_color(BLACK);
+    Bitboard b1, b2;
+    Square sq;
+    int n = 0;
+
+    // Captures in the a1-h8 direction:
+    b1 = (pawns << 9) & ~FileABB & enemyPieces;
+
+    // Promotions:
+    b2 = b1 & Rank8BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NE, sq, QUEEN);
+    }
+
+    // Non-promotions:
+    b2 = b1 & ~Rank8BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_NE, sq);
+    }
+
+    // Captures in the h1-a8 direction:
+    b1 = (pawns << 7) & ~FileHBB & enemyPieces;
+
+    // Promotions:
+    b2 = b1 & Rank8BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NW, sq, QUEEN);
+    }
+
+    // Non-promotions:
+    b2 = b1 & ~Rank8BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_NW, sq);
+    }
+
+    // Non-capturing promotions:
+    b1 = (pawns << 8) & pos.empty_squares() & Rank8BB;
+    while(b1)  {
+      sq = pop_1st_bit(&b1);
+      mlist[n++].move = make_promotion_move(sq - DELTA_N, sq, QUEEN);
+    }
+
+    // En passant captures:
+    if(pos.ep_square() != SQ_NONE) {
+      assert(square_rank(pos.ep_square()) == RANK_6);
+      b1 = pawns & pos.black_pawn_attacks(pos.ep_square());
+      assert(b1 != EmptyBoardBB);
+      while(b1) {
+        sq = pop_1st_bit(&b1);
+        mlist[n++].move = make_ep_move(sq, pos.ep_square());
+      }
+    }
+
+    return n;
+  }
+
+
+  int generate_black_pawn_captures(const Position &pos, MoveStack *mlist) {
+    Bitboard pawns = pos.pawns(BLACK);
+    Bitboard enemyPieces = pos.pieces_of_color(WHITE);
+    Bitboard b1, b2;
+    Square sq;
+    int n = 0;
+
+    // Captures in the a8-h1 direction:
+    b1 = (pawns >> 7) & ~FileABB & enemyPieces;
+
+    // Promotions:
+    b2 = b1 & Rank1BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SE, sq, QUEEN);
+    }
+
+    // Non-promotions:
+    b2 = b1 & ~Rank1BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_SE, sq);
+    }
+
+    // Captures in the h8-a1 direction:
+    b1 = (pawns >> 9) & ~FileHBB & enemyPieces;
+
+    // Promotions:
+    b2 = b1 & Rank1BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SW, sq, QUEEN);
+    }
+
+    // Non-promotions:
+    b2 = b1 & ~Rank1BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_SW, sq);
+    }
+
+    // Non-capturing promotions:
+    b1 = (pawns >> 8) & pos.empty_squares() & Rank1BB;
+    while(b1)  {
+      sq = pop_1st_bit(&b1);
+      mlist[n++].move = make_promotion_move(sq - DELTA_S, sq, QUEEN);
+    }
+
+    // En passant captures:
+    if(pos.ep_square() != SQ_NONE) {
+      assert(square_rank(pos.ep_square()) == RANK_3);
+      b1 = pawns & pos.white_pawn_attacks(pos.ep_square());
+      assert(b1 != EmptyBoardBB);
+      while(b1) {
+        sq = pop_1st_bit(&b1);
+        mlist[n++].move = make_ep_move(sq, pos.ep_square());
+      }
+    }
+
+    return n;
+  }
+    
+
+  int generate_white_pawn_noncaptures(const Position &pos, MoveStack *mlist) {
+    Bitboard pawns = pos.pawns(WHITE);
+    Bitboard enemyPieces = pos.pieces_of_color(BLACK);
+    Bitboard emptySquares = pos.empty_squares();
+    Bitboard b1, b2;
+    Square sq;
+    int n = 0;
+
+    // Underpromotion captures in the a1-h8 direction:
+    b1 = (pawns << 9) & ~FileABB & enemyPieces & Rank8BB;
+    while(b1) {
+      sq = pop_1st_bit(&b1);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NE, sq, ROOK);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NE, sq, BISHOP);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NE, sq, KNIGHT);
+    }
+
+    // Underpromotion captures in the h1-a8 direction:
+    b1 = (pawns << 7) & ~FileHBB & enemyPieces & Rank8BB;
+    while(b1) {
+      sq = pop_1st_bit(&b1);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NW, sq, ROOK);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NW, sq, BISHOP);
+      mlist[n++].move = make_promotion_move(sq - DELTA_NW, sq, KNIGHT);
+    }
+
+    // Single pawn pushes:
+    b1 = (pawns << 8) & emptySquares;
+    b2 = b1 & Rank8BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_promotion_move(sq - DELTA_N, sq, ROOK);
+      mlist[n++].move = make_promotion_move(sq - DELTA_N, sq, BISHOP);
+      mlist[n++].move = make_promotion_move(sq - DELTA_N, sq, KNIGHT);
+    }
+    b2 = b1 & ~Rank8BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_N, sq);
+    }
+
+    // Double pawn pushes:
+    b2 = ((b1 & Rank3BB) << 8) & emptySquares;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_N - DELTA_N, sq);
+    }
+
+    return n;
+  }
+
+
+  int generate_black_pawn_noncaptures(const Position &pos, MoveStack *mlist) {
+    Bitboard pawns = pos.pawns(BLACK);
+    Bitboard enemyPieces = pos.pieces_of_color(WHITE);
+    Bitboard emptySquares = pos.empty_squares();
+    Bitboard b1, b2;
+    Square sq;
+    int n = 0;
+
+    // Underpromotion captures in the a8-h1 direction:
+    b1 = (pawns >> 7) & ~FileABB & enemyPieces & Rank1BB;
+    while(b1) {
+      sq = pop_1st_bit(&b1);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SE, sq, ROOK);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SE, sq, BISHOP);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SE, sq, KNIGHT);
+    }
+
+    // Underpromotion captures in the h8-a1 direction:
+    b1 = (pawns >> 9) & ~FileHBB & enemyPieces & Rank1BB;
+    while(b1) {
+      sq = pop_1st_bit(&b1);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SW, sq, ROOK);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SW, sq, BISHOP);
+      mlist[n++].move = make_promotion_move(sq - DELTA_SW, sq, KNIGHT);
+    }
+
+    // Single pawn pushes:
+    b1 = (pawns >> 8) & emptySquares;
+    b2 = b1 & Rank1BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_promotion_move(sq - DELTA_S, sq, ROOK);
+      mlist[n++].move = make_promotion_move(sq - DELTA_S, sq, BISHOP);
+      mlist[n++].move = make_promotion_move(sq - DELTA_S, sq, KNIGHT);
+    }
+    b2 = b1 & ~Rank1BB;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_S, sq);
+    }
+    
+    // Double pawn pushes:
+    b2 = ((b1 & Rank6BB) >> 8) & emptySquares;
+    while(b2) {
+      sq = pop_1st_bit(&b2);
+      mlist[n++].move = make_move(sq - DELTA_S - DELTA_S, sq);
+    }
+
+    return n;
+  }
+
+  
+  int generate_knight_moves(const Position &pos, MoveStack *mlist, 
+                            Color side, Bitboard target) {
+    Square from, to;
+    Bitboard b;
+    int i, n = 0;
+
+    for(i = 0; i < pos.knight_count(side); i++) {
+      from = pos.knight_list(side, i);
+      b = pos.knight_attacks(from) & target;
+      while(b) {
+        to = pop_1st_bit(&b);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    return n;
+  }
+
+
+  int generate_bishop_moves(const Position &pos, MoveStack *mlist, 
+                            Color side, Bitboard target) {
+    Square from, to;
+    Bitboard b;
+    int i, n = 0;
+
+    for(i = 0; i < pos.bishop_count(side); i++) {
+      from = pos.bishop_list(side, i);
+      b = pos.bishop_attacks(from) & target;
+      while(b) {
+        to = pop_1st_bit(&b);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    return n;
+  }
+
+
+  int generate_rook_moves(const Position &pos, MoveStack *mlist, 
+                          Color side, Bitboard target) {
+    Square from, to;
+    Bitboard b;
+    int i, n = 0;
+
+    for(i = 0; i < pos.rook_count(side); i++) {
+      from = pos.rook_list(side, i);
+      b = pos.rook_attacks(from) & target;
+      while(b) {
+        to = pop_1st_bit(&b);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    return n;
+  }
+
+
+  int generate_queen_moves(const Position &pos, MoveStack *mlist, 
+                           Color side, Bitboard target) {
+    Square from, to;
+    Bitboard b;
+    int i, n = 0;
+
+    for(i = 0; i < pos.queen_count(side); i++) {
+      from = pos.queen_list(side, i);
+      b = pos.queen_attacks(from) & target;
+      while(b) {
+        to = pop_1st_bit(&b);
+        mlist[n++].move = make_move(from, to);
+      }
+    }
+    return n;
+  }
+
+
+  int generate_king_moves(const Position &pos, MoveStack *mlist, 
+                          Square from, Bitboard target) {
+    Square to;
+    Bitboard b;
+    int n = 0;
+    
+    b = pos.king_attacks(from) & target;
+    while(b) {
+      to = pop_1st_bit(&b);
+      mlist[n++].move = make_move(from, to);
+    }
+    return n;
+  }
+
+
+  int generate_castle_moves(const Position &pos, MoveStack *mlist, Color us) {
+    int n = 0;
+
+    if(pos.can_castle(us)) {
+      Color them = opposite_color(us);
+      Square ksq = pos.king_square(us);
+      assert(pos.piece_on(ksq) == king_of_color(us));
+      
+      if(pos.can_castle_kingside(us)) {
+        Square rsq = pos.initial_kr_square(us);
+        Square g1 = relative_square(us, SQ_G1);
+        Square f1 = relative_square(us, SQ_F1);
+        Square s;
+        bool illegal = false;
+
+        assert(pos.piece_on(rsq) == rook_of_color(us));
+
+        for(s = Min(ksq, g1); s <= Max(ksq, g1); s++)
+          if((s != ksq && s != rsq && pos.square_is_occupied(s))
+             || pos.square_is_attacked(s, them))
+            illegal = true;
+        for(s = Min(rsq, f1); s <= Max(rsq, f1); s++)
+          if(s != ksq && s != rsq && pos.square_is_occupied(s))
+            illegal = true;
+
+        if(!illegal)
+          mlist[n++].move = make_castle_move(ksq, rsq);
+      }
+
+      if(pos.can_castle_queenside(us)) {
+        Square rsq = pos.initial_qr_square(us);
+        Square c1 = relative_square(us, SQ_C1);
+        Square d1 = relative_square(us, SQ_D1);
+        Square s;
+        bool illegal = false;
+
+        assert(pos.piece_on(rsq) == rook_of_color(us));
+
+        for(s = Min(ksq, c1); s <= Max(ksq, c1); s++)
+          if((s != ksq && s != rsq && pos.square_is_occupied(s))
+             || pos.square_is_attacked(s, them))
+            illegal = true;
+        for(s = Min(rsq, d1); s <= Max(rsq, d1); s++)
+          if(s != ksq && s != rsq && pos.square_is_occupied(s))
+            illegal = true;
+        if(square_file(rsq) == FILE_B &&
+           (pos.piece_on(relative_square(us, SQ_A1)) == rook_of_color(them) ||
+            pos.piece_on(relative_square(us, SQ_A1)) == queen_of_color(them)))
+           illegal = true;
+                         
+        if(!illegal)
+          mlist[n++].move = make_castle_move(ksq, rsq);
+      }
+    }
+
+    return n;
+  }
+    
+}
diff --git a/