SjaakII/sjaakii.pod000644 000765 000024 00000004715 12470157255 015225 0ustar00eglebbkstaff000000 000000 =head1 NAME sjaakii - xboard-compatible chess and chess-variant engine 'SjaakII' =head1 SYNOPSIS B [-log|-newlog [filename]] [-variant name] [-no_user_variants] [-xboard|-uci|-uci|-ucci] [variant file] =head1 DESCRIPTION B is a program that plays chess and chess variants. It uses the xboard/winboard chess-engine protocol to communicate. Apart from normal chess, SjaakII can play Seirawan Chess, Mongolian Shatar, Makruk (including variants ASEAN and Ai-Wok), Shatranj, Sittuyin (Burmese Chess), Crazy House Chess, Chessgi, Spartan Chess, Pocket Knight Chess, King-of-th-Hill, Knightmate, Amazon Chess, Chancellor Chess, Berolina Chess, Los Alamos Chess, Micro Chess, Capablanca Chess, Gothic Chess, Embassy Chess, Courier Chess, Grand Chess, Opulent Chess, Omega Chess, Shogi (including variants Mini Shogi, Sho Shogi and Tori Shogi) and Xiang-Qi. Other variants can be added through a configuration file. See xboard(6) for instructions about how to use B through xboard. To start up quickly, you just need the command: B. Some of the variants SjaakII plays are only partially supported by XBoard, and can only be played whith the legality-testing function of the latter switched off. =head1 OPTIONS =over 8 =item B<-log [filename]> Append all communication by SjaakII and XBoard to a logfile. If no filename is specified, the log is written to sjaakii.log. =item B<-newlog [filename]> As B<-log>, but the file is overwritten rather than added to. =item B<-variant name> Normally, SjaakII starts with variant "normal" (regular chess), but it can be made to start with any other named variant with this option. =item B<-no_user_variants> Do not read the default variant configuration file. You can still specify a file in the engine options. =item B<-xboard> Start in xboard mode rather than the default mode. =item B<-uci> Start in UCI mode rather than the default mode. =item B<-usi> Start in USI mode rather than the default mode. =item B<-ucci> Start in UCCI mode rather than the default mode. =item B Read variant descriptions from the named file. =back =head1 AVAILABILITY From http://www.eglebbk.dds.nl/program/chess-index.html =head1 SEE ALSO xboard(6) =head1 STANDARDS WinBoard, B(6) interface ("Chess Engine Communication Protocol") =head1 AUTHOR Evert Glebbeek . This manual page was based on the man page for Fairy-Max by H.G. Muller and was generated with pod2man(1). SjaakII/COPYING000644 000765 000024 00000104513 12433144250 014124 0ustar00eglebbkstaff000000 000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . SjaakII/CHANGES000644 000765 000024 00000077417 12502304765 014106 0ustar00eglebbkstaff000000 000000 Between 1.0RC7 and 1.0.0: * include/game.h: Make sure SEE cache is initialised to 0 at startup. * include/piece_types.h: Use piece_bit_t to encode promotion choices. * include/chase.h: Fix chase detection: the retrieved from/to squares were entirely bogus. Avoid using get_move_captured_piece(). * include/move.h, include/see.h: Retire get_move_captured_piece. * include/move.h: Reduce size of pickup encoding to a single square. * include/movegen.h, include/variants.h, src/rules/move.cc: Add a prototype version of the Chu Shogi Lion to the test variant (as WFADN0 leaper). Add the ability to store a null-move to the move generator (implemented as a 0-jump). This is output as @@@@ in LAN. * include/move.h: Allow encoding of double captures (Lion moves). DO not reset 50 move counter on castling. Make move description agree with what is implemented. * include/variants.h: Add Lion definition to test game. * include/board.h, include/history.h, include/killer.h, include/move.h, include/search.h, include/see.h: Eliminate get_move_player. * include/movegen.h: Try to unwind some of the nested template code. This still does the same, but it leaves the job to the compiler. * include/movestring.h: Remove move_is_long_algebraic, it is no longer used. * src/xboard.cc: Add longmoves command, which prints out the moves in different formats. * include/piece_rules.h: Apply "cyclic" promotions on Shogi pieces: if a + piece is promoted, it reverts to its unpromoted state. * src/rules/move.cc, src/rules/san.cc: Correctly output "+" for "promotion" of promotion pieces (subject to change) * include/fen.h: Allow multi-character piece encodings in FEN strings. In particular, this allows ' and ! which are allowed extra characters in XBoard. * src/xboard.cc: Backport UCI ponder fix from Jazz. * src/xboard.cc: Remove stray ; * include/game.h: Push pawns more agressively in drop games, since we cannot rely on game phase to activate an end-game term for this. * include/eval_param.h, include/game.h: Add general quadratic terms for pawn advancement in piece square tables. The only term currently in use is the quadratic end-game term, but at least the linear MG term may be useful to have as well. * include/search.h: Remove unused maxdepth/seldepth output. * include/board.h, include/movegen.h, include/variants.h, src/rules/move.cc, variants.txt: Allow promotions on drop moves. Allows for the implementation of Kyoto Shogi. * include/game.h, include/movegen.h, include/piece_types.h: Use 32 bit integers for piece masks, since we now have 32 piece types. Between 1.0RC6 and 1.0RC7: * include/board.h: Trap illegal square numbers being passed to board.get_piece() in debug mode. * include/game.h: Reflect changes in castle rights in the hash key. This needs to be done in "playmove" rather than "makemove" because "makemove" does nt have access to the move generator. * include/fen.h: Correct presence of castling and en-passant fields in FEN string for whether these moves occur in a game. Correct full-move counter output in FEN. * include/movegen.h: More direct and explicit test of whether promotion moves out of the promotion zone are allowed or not. Again, this should perhaps be a separate flag in the future, instead of being implied by RF_PROMOTION_IN_PLACE. * src/xboard.cc: Fix Sittuyin test positions. * include/see.h: Do not order non-captures by LVA. This seems to cause problems with optimised builds under Windows. * include/movegen.h: Print an error message if a config file defines too many pieces. * include/movegen.h: Separate leaper and aleaper counts. * include/game.h: Avoid floating point exception when assigning a scaled piece value with a scale of 0 * include/movegen.h: Proper re-use of stepper descriptions/indices. * include/game.h: Print number of pieces of a particular type as output of pieceinfo. * include/betza_string.h, include/movegen.h: Rewrite matching of leaper moves to more efficiently reuse existing entries. The code is now simpler as well. * include/movegen.h: Rewrite matching of aleaper moves to more efficiently reuse existing entries. The code is now simpler as well. * include/variants.h: Promotions are not optional in Makruk. Between 1.0RC5 and 1.0RC6: * src/xboard.cc: Fix compilation if readline is not available. * include/movegen.h, include/piece_rules.h, include/piece_types.h, include/variants.h: Fix a problem in Tori Shogi: the drop-rule states a sparrow may not be dropped on a file that has *two* friendly sparrows. * include/evaluate.h: Disable game-phase interpolation for variants where captured pieces are returned to the board: material on the board does not reflect game phase in this case. * include/movegen.h: Fix a problem with promotions in Shogi: pawn moves out of the optional promotion zone are not optional. * include/movegen.h: Better fix for optional promotions in Shogi that does not potentially break EuroShogi. * include/move.h: Replace hard-coded numbers with symbolic constants for shifts and masks when building up the move struct. * include/move.h: Replace more hard-coded numbers with symbolic constants for shifts and masks when building up the move struct. * include/move.h: Replace more hard-coded numbers with symbolic constants for shifts and masks when building up the move struct. * include/move.h, include/pieces.h: Replace hard-coded numbers with symbolic constants for shifts and masks when building up piece IDs. * include/board.h, include/pieces.h: Remove almost unused piece_t. This also fixes a hidden conversion of unsigned->signed. * include/game.h, include/movegen.h, include/piece_types.h, include/search.h: Do not defer promotion (in the search) if this is unneeded because the unpromoted piece has a subset of the moves of the promoted piece. Mainly affects Shogi-like variants. * include/piece_types.h, include/pieces.h: Use typedef for piece bitfields (instead of uint16_t). * include/movegen.h: Replace 0xffffffff by ~0 for bitmasks representing piece-sets: this makes it agnostic of the size of the bitmask. * include/movegen.h: Reuse leaper tables more efficiently by just looping over existing tables at the end (the clever way that avoids this doesn't seem to actually work, and only captures a sub-set anyway). Also fixes a bug where defining a new leaper could clear the aleaper tables. * include/movegen.h: Reuse stepper descriptions in the same way as leaper descriptions. * include/movegen.h: Make sure piece-type masks have enough space. * include/movegen.h, include/pieces.h: We do not need to keep track of the number of sliders and hoppers; to construct the super slider/hopper we only need to keep track of the joined move flags. * include/move.h: Re-use piece side encode/decode in move decoding. * include/move.h, include/see.h: Fix a bug in MVV/LVA ordering: make sure a move is a capture move before extracting a captured piece. * include/betza_string.h: Betza notation for drop moves (future-proofing for XBoard). * include/variants.h: Handle arbitrary-length pieceToChar strings in input file. * include/search.h: Fix cosmetic typo: use hash_move when storing the counter-move table. * include/game.h: Cleanup. * include/board.h: Keep track of a separate hash key for the board hash (in addition to the full hash). * include/search.h: More agressive pruning of futile drops near the leaves of the tree. * include/search.h: Always accept mate scores from the TT, independent of remaining depth: more depth is not going to alter the mate result... * include/search.h: Offer a draw if the game lasts extremely long (> 400 moves). This may take some 8 moves or so to trigger for the first time. * include/board.h, include/fen.h, include/game.h, include/search.h: Implement detection of "pseudo-repeats" in drop games: these are repeats where the position is repeated, but the holdings are not. In a typical case, we may be leaking pieces to the hand of the opponent - which means we are now worse off than we were when the position occurred last. If this situation is detected, we simply fail low immediately at this node. * include/variants.h: Handle arbitrary-length pieceToChar strings in input file: now without crashing (the required size was calculated incorrectly). * include/movegen.h: Fix generation of evasions if the checker is a lame leaper (which can be blocked). This caused Sjaak to miss some possible evasions. * src/xboard.cc: Switch to force mode after setboard. This is safe to do, but not strictly specified in the protocol. * include/evaluate.h, src/xboard.cc: Add another Xiangqi test position, this one testing evasion by blocking a lame leaper. * include/evaluate.h: Revert accidental inclusion of change in evaluate.h in last commit. * include/eval_param.h, include/game.h: Implement framework for piece value scaling of defensive pieces with game phase. Swap the test for defensive pieces and lame leapers. * include/game.h: Fix calculation of pair bonus for defensive pieces, which was completely wrong (resulting in a bonus that was larger than the piece value). * include/eval_param.h: Decrease the value of defensive pieces in the end game. This encourages advancing the game phase (exchanging attacking pieces) if we are behind an attacking piece for a defensive piece, and discourages simplification to dead-drawn endings where the advantage consists entirely of defensive pieces. The end point of the scale (0.8 of the nominal value) has not been tuned. * include/movegen.h: If promotions are flagged as in-place, disallow optional promotions by moving out of the promotion zone. Fixes a bug in Sittuyin that allowed them. * src/xboard.cc: Modularise testing of move generator. Add Sittuyin test position, to handle drop promotions. * variants.txt: Add three (four) contributed variants: Euro Shogi, Yari Shogi and Goro goro Shogi (with and without knight/lance in hand). Thanks to Harm-Geert Muller and Keith White. * include/move.h: Make move format description match what is actually implemented in the code. * include/pieces.h: Increase number of allowed pieces to 32 (up from 16). * include/evaluate.h: Revert Shogi forward king-safety patch. It is a regression at longer time controls. * include/search.h: Change repetition detection: if the first repetition is in the game history (as opposed to search) do not automatically score the second repetition as a draw if it occurs in the search. * src/xboard.cc: Fix a cosmetic mistake when listing variant names for the "Fairy selects" option (stray ,). * include/movegen.h: Generalise castle mask code to work along general rays (not just ranks) * include/fen.h: Make FEN parsing of castle moves work if king and rook are not on the same rank. * variants.txt: Fix board FEN for Troitzky Chess to include dark squares. * variants.txt: Fix board FEN for Troitzky Chess to not list castling. * include/movegen.h: Guard against accidentally setting off-the-board squares. * variants.txt: Added the 'Byway' setup as an alternative to the 'Jelliss' setup for Troitzky Chess. This implements castling with a rook that is not on the same rank. This will NOT work in XBoard. * include/variants.h: Rename Marshall->Marshal. * include/game.h, include/movegen.h, src/xboard.cc: Make rules include pawn doubl-pushes in board output. Add a special "wikirules" command that prints out the rules in a template suitable for putting on a wiki. * include/game.h: Fix wiki formatting for bullet lists. * include/game.h: Add templated note about rules being auto-generated. * include/variants.h: Fix promotion in Shatranj: to queen (ferz) only. * include/variants.h: Fix white promotion zone in Gardner Minichess. * variants.txt: Fix promotions in Omicron Chess to include Wizard and Champion. * include/game.h: Tweaks to Wiki-output for rules. Add a section on promotions, with boards indicating the promotion zones. * include/game.h: Clarify drop rules in rule description. * include/game.h: Tweaks to wiki-fied output. * variants.txt: Fix Black promotion zone for Peasant's Revolt. Cosmetic fix for Corner Chess. Between 1.0RC4 and 1.0RC5: * include/move.h: Fix a bug in decoding the move piece. This seems to have mainly had cosmetic effects, but it is an actual bug that could trip up move matching and things like SEE. * include/piece_rules.h, src/rules/move.cc, src/rules/san.cc: Correct SAN output of piece symbol for promoted pieces in Shogi. * variants.txt: Mark perpetual check as illegal in Judkins Shogi. * include/game.h, include/piece_rules.h, include/piece_types.h, include/variants.h, variants.txt: Allow specifying of the optional promotion zone, prison and drop-zones from the configuration file. Add a new piece property, "drop dead", which means the piece can be dropped in locations where it has no legal moves. * src/xboard.cc: Fix missing strdup(). * include/search.h: Fix overzealous pruning of drops near the root to finish a 1-ply search: doing it at greater depth leads to ugly and misleading analysis from shallow searches. * src/xboard.cc: Add protocol extension load and unload commands, to load variant definitions on the fly. * src/xboard.cc: Invalidate a file before loading it again. * include/search.h: Code cleanup: put code to score moves in the move list in its own function. * include/search.h: Replace static capture search with actual q-search. * include/move.h, include/search.h, include/see.h: Fix a major bug when extracting the side that moved from a move: it was always extracted as white. This completely broke SEE for black, and broke history and counter-move tables as well by lumping all moves from both sides together. Add proper SEE evaluation of drop moves. * src/xboard.cc: Print the correct repetition count for N-fold repetition (instead of just 3) * include/board.h, src/xboard.cc: Add "(debug)" to the version number of debugging builds. Add an extra sanity-check/assert in makemove. * include/search.h: Re-organise code for pruning decisions. This is a bit cleaner, and allows us to avoid calculating the static evaluationif it is not needed. * include/search.h: Get rid of the beta==alpha-1 condition on razoring. First of all it is a bug (should be beta==alpha+1), second of all, razoring in PV nodes is perfectly fine. * include/fen.h, include/game.h, include/movegen.h, include/piece_rules.h, include/piece_types.h, include/pieces.h, include/variants.h, src/xboard.cc: Fix parsing of initial state in FEN positions. There was a bug that could cause both castle flags to be set if one of them was, and the parser did not work correctly for Seirawan-style strings. There are a number of caveats with this though, for the interaction between backrank virgin pieces and castling rights in s-FEN. There may also be issues with shuffle variants on large boards (where 'k' denotes a rank, but 'k' is also used to indicate castling rights in Omega chess, for instance). * include/eval_param.h, include/evaluate.h: Award a penalty to a loose minor (a minor that is not defended by a pawn), scaled with the number of super pieces. * include/search.h: Fixes for analysis mode: do not break out early if mate is found or if there is only one move in the current position. If we do reach the end of the line, just wait until we're told to exit analysis mode. Otherwise the engine starts spamming the GUI over and over again until something breaks and things crash. * include/search.h: Fixes for analysis mode: do not break out of the analysis loop if asked to analyse in a checkmate position. This floods the output queue. * include/fen.h: Make sure king_from was set before trying derive castle flags from it. * include/game.h, include/piece_types.h: Add a function to guestimate piece values if none are specified. * include/fen.h, include/movegen.h: Make sure variables related to castle moves that are not defined in a variant are well-defined. * include/evaluate.h, include/variants.h: Scale piece-values in Shogi by 0.25. * include/variants.h: Tune scale-factor for material in Shogi. * include/game.h: Tune scale-factor for material in Shogi. * include/game.h: Minor tweaks to the piece value guestimator to try to give a better indication of piece strength for asymmetric pieces (it now scores shogi-knight ahead of shogi-lance) as well as take into account the elephantiasis of all pieces promoting to gold generals in shogi. * include/eval_param.h, include/evaluate.h: Parameterise space advantage. * include/eval_param.h, include/evaluate.h: Minor refactoring and code cleanup for evaluation. * include/evaluate.h: Prophylactic commit: penalise the king shelter in shogi if there are empty squares in front of the king. This is a very clear gain at slow time controls, less so at long time controls (test is still running, but doesn't look bad - it's still better). * src/xboard.cc: If reading input from a file rather than a terminal, skip comments. * include/variants.h: Fix parsing of optional promotion zones from the input file. * include/movegen.h: If a move originates within the promotion zone, but not the optional promotion zone, disallow generation of regular move. * src/rules/san.cc: SAN output: no need to disambiguate with respect to drop moves. * include/variants.h: Ensure that the promotion zone includes the optional promotion zone, if both are set from the config file. * include/fen.h, include/game.h, include/search.h: Two unrelated things: 1. Detect (some) mates in quiescence search: if the path leading to mate consists entirely of check/evasion moves, then the mate score from quiescence can be trusted and returned. 2. Record the correct full-move number from the startup FEN (instead of always behaving as though it were 1). * include/movegen.h: Add a special staged move generation. This is as yet not used much, but it could be. * include/mate.h, include/search.h: Add special mate-search code: this is a special search function that uses the staged move-generator. It returns either a mate-score (which is accurate) or a non-mate score (which is arbitrary and should be treated as an indication to continue the regular search). * include/fen.h, include/search.h: Fix parsing FEN records that do not include an en-passant square: we don't want to skip over the next field in that case. * include/mate.h, include/search.h: Make sure the mate-search is aborted if time runs out. * include/search.h: Fix move number in PV output with black to move. * include/search.h: Do not break out with a mate score based on the depth of the iteration matching the mate score, but based on the length of the PV matching the distance to mate. * include/search.h: Perform a special mate-search close to the root or at great depth in drop variants. Tests as a mild improvement there, can probably be tweaked for more. * include/game.h, include/search.h, src/xboard.cc: Add an option to enable/disable the special mate search. * include/search.h: Allow for future expansion of the mate-search options. Between 1.0RC3 and 1.0RC4: * include/board.h: Avoid warning about shadowing a member variable of the same name. * CMakeLists.txt: Fix make install target for manpage. * include/game.h, src/xboard.cc: Fix handling of commands in analysis mode: commands that should act on the root position should not be handled until after we return from the search. * src/xboard.cc: Add some FRC/Chess960 castling test positions from Reinhard Scharnagl. * src/xboard.cc: Report depth for expected perft positions. * src/xboard.cc: Fix a mistake in the perft count for one of the new FRC test positions. * include/board.h: Fix a design flaw in makemove: also for swaps, the destination squares need to be cleared before we resolve the drop side of the swap. Not doing this will corrupt the board state in FRC castle positions where the king moves to the rook square. * include/fen.h: Correct FEN output strings for boards with virtual ranks/files and holes. Fix a bug where the 50-move counter would be wrong (~arbitrary) for FEN strings that didn't include the field. * include/betza_string.h: Fix a bug in the generation of Betza strings for steppers: the direction masks for the Ferz were not properly calculated, leading to a buggy definition of the pawn move in Legan Chess (mF rather than lfmF). * include/game.h, src/xboard.cc: Keep track of time at each move, so the program will keep proper time during takenback/undo. * src/xboard.cc: Remove temporary debugging print statement. * include/test_suite.h: Expand STS test suite positions to include the full range of positions. * include/test_suite.h, src/xboard.cc: Add STS 13 and 14. Avoid hanging the program in case of a bad testsuite string. Print number of positions that got awarded points (regardless of whether the score is optimal or not) in the intermediate outout. * include/variants.h, src/xboard.cc: Add Great Shatranj as a known variant. http://hgm.nubati.net/rules/Great.html or http://www.chessvariants.org/index/msdisplay.php?itemid=MSgreatshatranjm * include/variants.h, src/xboard.cc: Add Superchess. XBoard has a bug in that it will publish castling rights if no corresponding rook is present, which will probably mess us up. Fix missing limit on number of black pieces in Great Shatranj. * include/variants.h, variants.txt: Allow specifying the maximum number of a particular piece type in the configuration file. * variants.txt: Rename Judkins Shogi -> Judkins' Shogi. This changes the short name to 'judkins'. * src/xboard.cc: Unload the user-defined variant config file before loading a new one. Reset the options that are sent to XBoard, which updates the variant list. * src/xboard.cc: Allow changing whether user-defined variants are listed first or not through a config options. This is useful because the XBoard variant dialog box is not large enough to contain all build-in variants and all user-defined variants defined in the standard config file, so some of them will be pushed out. * include/movegen.h, src/xboard.cc: Minor cleanup of leaper move generation: use bitboard generation functions where they exist. * include/bitboard.h, include/movegen.h: Minor cleanup for calculating "in-between" squares along a ray. Move #define update_leaper_bb to before make_aleaper_bitboard(). * include/search.h: Spacing of PV output in standard mode. * sjaakii.pod, src/xboard.cc: Add -xboard/-uci/-usi/-ucci commandline options to start the engine directly in a particular mode. These aren't really needed, but they serve to suppress the board/prompt output, which may be desirable for some interfaces. * include/evaluate.h: Document purpose of evaluation term attacking flags. * src/xboard.cc: Fix highlight FEN on normal (non-virtual/omega) boards, which were broken by the fix that made them work for Omega (duh). Fix using input[1] to determine the UCI dialect if -uci/usi/ucci are passed as startup options (reported by Martin). * src/rules/san.cc: Fix a bug in the output of SAN moves: the disambiguation didn't work correctly if the alternatives were a regular move and a promotion move: the code would still end up trying to 'disambiguate' by file and rank, rather than by promotion/no promotion. * include/movestring.h: Discard '=' token as optional when parsing a string. It is used as a promotion deferral in Shogi, or sometimes in variants of SAN to indicate promotion. Either way, we don't need it, so just skip it. * src/xboard.cc: Make it possible to defer commands received while thinking until after we have broken out of the thinking loop. Fixes cases of Sjaak ignoring 'new' while it is thinking, but giving the impression that it handled the command (by responding to ping with the proper pong). * include/evaluate.h: Include a space-advantage term, as suggested in http://www.talkchess.com/forum/viewtopic.php?p=609260. No measurable improvement in regular chess, but a massive plus for Gothic chess. * src/xboard.cc: Fix an issue with colour-FENs: if there is an optional promotion, the colour of the target square used to depend on the order in which moves are generated. This is no longer the case now, and the square gets the colour for promotion in preference to its default colour. * include/variants.h, variants.txt: Allow setting of the number of repeats required to trigger the "repeated position" end-game condition from the config file. * include/game.h, include/search.h, include/variants.h, src/xboard.cc, variants.txt: Implement triggering of no_pieces game-end condition. * include/game.h, include/search.h, src/xboard.cc: Implement resign and draw offer code (disabled by default) * include/game.h, include/search.h, src/xboard.cc: Optionally supress the claiming of repetition draws. * include/movegen.h: Do not generate drop moves in QS: they are pruned anyway (for now). * include/game.h, include/search.h, include/variants.h, src/xboard.cc, variants.txt: Score "perpetual" seperately from "repeat" (but the same by default). Try really hard to finish the first iteration (up to possibly using all our available time) to avoid the situation where we end up with no move to play. * include/game.h, include/search.h: Use finer granularity in clock-testing for drop variants. If we cannot complete the d=1 iteration, prefer to use a move from the hash table to playing a random move, if there is one. Between 1.0RC2 and 1.0RC3: * CMakeLists.txt, include/bitboard.h, include/eval_types.h, include/evaluate.h, include/game.h, include/killer.h, include/move.h, include/movegen.h, include/search.h, include/see.h, include/variants.h, src/xboard.cc: Fix many compiler warnings. Enable warnings by default. * include/movestring.h: Fix disambiguation of castling move when a piece is gated in. * include/fen.h: Ignore squares marked * in a FEN: these are meant to be void (off-board) squares * src/xboard.cc: Include promotions in the highlight colour FEN. * include/bitboard.h, include/board_rules.h: Fix the double-use of board_files[0] as the file_mask: this will not work correctly if a variant deletes squares from the file. * variants.txt: Fix a mistake in the definition of Judkins Shogi: the drop restrictions for pawns were accidentally applied to promoted pawns instead. * variants.txt: Add a new variant: Omicron Chess, which is like Omega Chess but on a 12x10 board rather than 12x12. Castling is disabled for now and off-board squares are not marked as "dark" to avoid crashes in XBoard (this should be purely cosmetic). * variants.txt: Replace Wizard pictograph with Wazir (instead of Vortex Chancellor) * src/xboard.cc: Get rid of __DATE__ in output because it causes binaries built on different dates to test as different even if they're not. Change order of variants in XBoard variants tag so variants from config files are listed first. * variants.txt: Remove outdated and misleading comment. * CMakeLists.txt, src/timer/timer.c: Don't try to use the realtime clock if we can't link to librt. * CMakeLists.txt, src/timer/timer.c: Better detection of clock_gettime. * variants.txt: Set Omicron Chess FEN to black out the deleted squares. * src/xboard.cc: Add a config option to mark holes in the board in the FEN sent to XBoard. Needs 4.8+ to work correctly, or XBoard will crash. The option is disabled by default for this reason. * src/xboard.cc: Flip the default for "mask dark squares" from true to false. This means a work-around needs to be enabled for XBoard 4.8 * include/board.h, include/fen.h, include/movegen.h: Rename ep_capture->ep_victim. It is clearer. * include/movegen.h: Not all instances of ep_capture referred to the victim (which is yet another reason to change the name). Change instances where it referred to the destination square accordingly. * include/board.h, include/fen.h, include/movegen.h: Replace en-passant square with a bitboard. The idea is that this can hold multiple en-passant squares, for large variants where pawns can move three ranks on their first step (such as Omega Chess) * include/board_rules.h, include/fen.h, include/game.h, include/movestring.h, include/squares.h, src/rules/squares.cc: Loosen the connection between the square ID in the FEN string and the bit index on the board. This allows us to make mangled boards, like for Omega Chess, that are larger than 128 bits. Better (more robust) identification of LAN strings. More accurate square-string matching. * include/variants.h, src/xboard.cc: Add Omega Chess (not enabled). It works, after a fashion, by hacking the movement tables so we can fake the 12x12 on a 12x10 board. Castling is missing (no real reason, but XBoard can't do it), SAN input is likely broken, board output is broken (it displays the mangled internal view of the board) and detecting of mate potential does not work (the routine is not designed with holey boards in mind). * include/game.h, include/variants.h, src/xboard.cc, variants.txt: Add a "Xboard parent" tag for variants defined in the config file. Needed because "fairy" does not always work correctly. * include/chase.h: Fix "may be used uninitialised" warning. * include/game.h, include/movegen.h: Apply board mask to leaper tables, otherwise "holes" in the board will not be masked out. This is not a problem during play, because the move generator applies the mask anyway, but it breaks mate potential detection and is generally sloppy. Fix a few issues in the mate potential detection: the defending king is allowed an entire quadrant (to take into account boards with holes, where we may not just be able to stick the king in a corner), but the corner and edge are tested first for efficiency reasons. Discard positions where the attacking king blocks all escape squares by itself: such positions are unreachable in legal play. They occur in the analysis of Omega Chess and Knightmate. * include/betza_string.h, include/variants.h, src/xboard.cc, variants.txt: Enable castling in Omega and Omicron Chess. * include/game.h: Fix detection of mating pairs and mate-potential assesment in Omega Chess. It fails to detect that a rook cannot force mate. * src/xboard.cc: Send multi-leg moves in two consecutive lines. Not that we generate those at the moment. * include/game.h, include/movestring.h, include/xstring.h, src/xboard.cc: Simplify matching of move string to move: instead of parsing the string, simply convert all legal moves to a string and test if the strings match. This is much less error-prone. * include/xstring.h: Add missing header files. * include/board.h, include/fen.h, include/game.h, include/piece_rules.h, include/variants.h, src/rules/squares.cc: Change the way the board is printed so "virtual" boards are printed accurately. So far, this only affects the output for Omega Chess. * src/xboard.cc: Fix a bug in the formatting of the variant list that is printed in response to "variants". * include/board.h, include/game.h: Unify the board.print() and board.print_demo_board() routines. * CMakeLists.txt, sjaakii.pod: Add a basic manpage. * CMakeLists.txt, src/xboard.cc: Rename SVNVERSION->SJAAKIIVERSION. SjaakII/README000644 000765 000024 00000010100 12462364731 013747 0ustar00eglebbkstaff000000 000000 Sjaak II - the next-generation general chess-like game playing program Copyright (C) 2011, 2014 Evert Glebbeek (eglebbk@dds.nl) Getting started --------------- To compile Sjaak, you will need: * A C++ compiler that understands some C99 constructs, for instance gcc (standard on Linux and Mac OS X, available for Windows in the form of MinGW) * CMake, a cross-platform setup and configuration system. Version 2.4 or better. * GNU Make. Technically this is optional and you could pick another back-end in CMake. For optimal performance, you will also need * A 64 bit operating system and compiler Configure Sjaak using CMake, either using cmake-gui, or from the command line. From the top-level Sjaak/ directory, run $ mkdir Build $ cd Build $ cmake .. Then run $ make This will place all generated files in the Build/ subdirectory, leaving the source tree clean. On Windows, substitute mingw32-make for "make". The program is called "sjaakii". You can load this as an engine in XBoard/Winboard, or use it directly as a terminal program. License ------- With a few exceptions (listed below), the source-code of SjaakII is released under the terms of the GNU General Public License (GPL) v3.0. A copy of the licence text is included in the file COPYING, or available from the Free Software Foundation at http://www.gnu.org/licenses/gpl.html The source-file src/misc/genrand.c is based on the 1997 implementation of the Mersenne Twister by Makoto Matsumoto and Takuji Nishimura and is released under GPL v2.0. The source files src/misc/cfgpath.c and include/cfgpath.h are based on public domain code by Adam Nielsen and are free for use without restriction. Castling, en-passant captures and repetitions --------------------------------------------- In chess, a position is not repeated if the en-passant capture rights are different between the two positions, even if all places are otherwise in the same position. The same goes for castling rights. To take this into account, it is necessary to fold the rights into the position signature. Sjaak currently does not do this, possibly leading to incorrect draw claims. This will not generally be a problem and it's a lot of hassle to code these things in for the general case. So it's omitted. For the en-passant square, we'd have to know the type of enemy piece that could capture en-passant, which in general we don't. Q&A --- Q: What is Sjaak? A: Sjaak is a general framework for playing chess-like games. It is basically a chess program that can play chess as well as a number of chess variants. Q: How do you pronounce that? A: Similar to French "Jacques". I chose the name because it sounds somewhat similar to what the common root of chess ("schaak" in Dutch), Chaturanga, Shatranj or Xiang-qi might sounds like. Appropriate for a program that plays general chess-like games. Q: Is Sjaak based on other programs? A: The move generator, evaluation function and search function were written from scratch, but the overall structure of the program and the data structures it uses are very heavily based on those I use in my normal chess program, Jazz. In fact, the code is so similar that I later copied parts of the code from Jazz to Sjaak with little or no modification, and so the programs are very similar in many ways. I would say they are siblings. The move structure in Sjaak is inspired by a description of the move structure of ChessV on TalkChess. Smooth scaling of the evaluation when approaching a 50-move draw as well as not using the score from the transposition table in that case is an idea picked up from Crafty. Q: Why doesn't Sjaak play atomic/losers/giveaway chess? A: A number of reasons. First of all there's another unrelated program by the same name that plays thsoe variants (and I even looked to see whether the name was used before I chose it). Having two programs with the same name playing the same game would be a bit confusing. Second of all, I'm really not that interested in these variants. Third, I'd need to make some modifications to the move generator and the way moves are stored, which I'm not inclined to do in light of the second point above. SjaakII/variants.txt000644 000765 000024 00000117120 12502304433 015455 0ustar00eglebbkstaff000000 000000 # Sjaak, a program for playing chess variants # Copyright (C) 2011, 2014 Evert Glebbeek # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This is a variant description file for Sjaak. # It can be used to configure Sjaak to play a chess variant by specifying the movement mode of the pieces. # Empty lines and anything following a # character are ignored. # To define a variant, begin a line with "Variant: ", then follow on subsequent lines with descriptions # of the board, the pieces used and their movement, and other rules used in the variant. # There are a number of examples below, but first we'll go into some background. # THE BOARD AND ZONES # # The board size is specified by (files)x(ranks), for instance # Board: 8x8 # defines a standard chess board. There are some limits on the size of a board: the number of files # and ranks needs to be smaller than 16 and the total size of the board needs to be less than 128 # squares. It is currently not possible to define boards that are smaller than 8x8 (this will be added # eventually). # For some of the rules, it's necessary to identify a part of the board. This is done by defining a "zone", # which lists the squares on the board that are part of that zone. # For instance: # Zone: rank2 = a2,b2,c2,d2,e2,f2,g2,h2 # Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 # defines the 8th rank (rank8) of the board. # Files are identified by letters, "a" being the first. Ranks are labelled by numbers, starting at "1". # The square "a1" is in the lower-left hand side of the board. # Two special zones, "empty" and "all", are pre-defined. As the names indicate, "empty" corresponds to an # empty board while "all" corresponds to the entire board. # # It's possible to exclude certain regions of the board. Moves are never generated from or to these squares: # Exclude: g1,h1,g2,h2,g3,h3,g4,h4,g5,h5,g6,h6,a7,b7,c7,d7,e7,f7,g7,h7,a8,b8,c8,d8,e8,f8,g8,h8 # excludes the last two rows and the rightmost files on the board, effectively reducing the board to 6x6. # # For some games, the victory (or drawing!) condition can be to occupy a specific region of the board. # This is referred to here as "capture the flag". To enable this, a special zone has to be defined for each # player, WhiteFlag for white and BlackFlag for black: # WhiteFlag: e1 # BlackFlag: e8 # The game ends when white captures and holds all black flags and vice versa. # PIECES # # Piece descriptions start with a "Piece:" line. On following lines the piece move and special properties can # be defined. # MOVEMENT TYPES # # In order to define new variants, it is important to know how to specify the movement of the pieces. # Sjaak distinguishes three types of moves: # # Sliders - move along a ray direction until they encounter another piece or the edge of the board # Leapers - perform single steps to specified target squares # Steppers - perform single (repeated) steps in a particular board direction # # Each of these moves treats the board in a slightly different way, and so the description of moves for each # is different: # # Sliders move along a ray, either horizontal (H), vertical (V), diagonal (D) or anti-diaginal (A). # Examples: # slide (H,V) - describes a chess rook # slide (A,D) - describes a bishop # slide (H,V,A,D) - describes a queen # # Leaper moves can become complicated, but in their simplest form they just specify the step-vector, which is # then mirrored to give a total of up to 8 target squares. # Examples: # leap (2,1) - describes a knight # leap (1,2) - alternative description of a knight # leap (1,1) - describes a ferz # leap (2,2) - an elephant # leap (1,0) - a wazir # leap (2,0) - a dabbabah # The complications begin when a piece is a compound leaper, meaning it can choose between different leaper # moves. For instance, a king can move as a ferz, or as a wazir: # leap (1,0)|(1,1) - a king # However, a leaper can also be a two-step leaper, which first moves as one type of leaper and then again as # another type of leaper: # leap (1,0)+(1,1) - move as a wazir first and then as a ferz # Typically, this is useful to define lame leapers by also specifying a mask: # leap ((1,0)+(1,1)) & (1,2) # describes a piece that moves first as a wazir (only to empty squares) and then again as a ferz. However, # the final destination must be a square that could have been reached by a knight. In other words, this # describes a piece that moves like a knight, but can be blocked. A Xiangqi horse. # # For steppers, board directions are indicated by compass points, so "north" (the side of the board where # black starts out), "south" (where white starts), "east" (the king-side, the direction of the H-file) and # "west" (towards the A-file). # Steppers are intended to be asymmetric (the move description is for white and mirrored for black), # step N - describes a piece that moves one square "north", a white pawn # step S - describes a piece that moves one square "south", a black pawn # Optionally, the direction can be prefixed with a number (1-7): # step 2N - the initial double step of a white pawn. # Steppers are normally used to define pawns, and a number of pawn-specific evaluation terms are only # activated for pieces that are defined as stepper moves. Steppers also have their moves generated in bulk, # one direction at a time (as opposed to one piece at a time), which impacts performance. # # Finally, there are two variations to the three above movement types: hoppers and asymmetric leapers. # # Hoppers are sliders that need to jump over another piece before they can move. # hop (H,V) - describes the capture move of a cannon in Xiangqi # Currently, capture is replacement only. It is not possible (yet) to define a piece that captures by leaping # over its victim. # # Asymmetric leapers are leapers that, as the name implies, move differently for white and black. # Their syntax is similar to that of normal leapers, but instead of specifying the movement vector, it's # necessary to specify each step: # aleap (0,1) - a piece that moves one square north for white and one square south for black (like a pawn) # aleap (1,1)|(1,-1)|(-1,-1)|(-1,1)|(0,1) - a Makruk elephant or silver general # aleap (1,1)|(-1,1)|(1,0)|(-1,0)|(0,1)|(0,-1) - a gold general # MOVES AND CAPTURES # # A piece can have more than one movement type defined for it, simply by specifying them one after the other # on separate lines: # # Move: slide (H,V,A,D) # Move: leap (1,2) # # defines the move for an Amazon. The move types must be different on each line, or the result will be # undefined. # If a capture move is not specified, it is assumed to be the same as the normal move. To disable captures for # a particular piece type, specify "none": # # Capture: none # Piece cannot capture # SPECIAL MOVES (DOUBLE PUSHES) # # For pieces that can perform special moves, it's necessary to specify both the move and the location on the # board where they can make the special move. This is done by defining a zone and then referencing it from the # piece description: # Special: rank2, rank7, step 2N # defines the initial double step for a white pawn (on rank 2) and a black pawn (on rank 7). # Special moves currently cannot be captures, and do not depend on whether the piece has moved or not. # SPECIAL MOVES (CASTLING) # # Castling is a special move where two friendly pieces move. It is only possible if neither of the two pieces # has moved already. All squares between the initial and final positions of the two pieces must be empty # (apart from the two pieces themselves). # If the primary castling piece is royal, then all squares between the king's initial and final position must # be "safe". # To define a castling move, specify the (default) starting position of the king, the king's destination # square and the secondary's (default) starting position. The secondary's destination square is derived from # the king's move: if the king moves to the king-side (east side) of the board, the secondary moves to the # left of the king. If the king moves to the queen-side (west side) of the board the secondary moves to the # right of the king. # Example: # # Castle: white e1-g1 with h1 # Canonical king-side castling # Castle: white e1-c1 with a1 # Canonical queen-side castling # # To define FRC-style castling, simply define the "standard" castling rule (which provide the destination # square for the king and the default location of the rook). The FRC rule will be based on this # and the actual specified position of the king and rook in the startup FEN. # Behaviour is undefined if all squares are not on one rank. # RESTRICTING MOVEMENT # # It is possible to restrict the movement options of a piece by specifying the locations it is allowed to move # to: # Zone: white_palace = d1,e1,f1, d2,e2,f2, d3,e3,f3 # Zone: black_palace = d8,e8,f8, d9,e9,f9, d10,e10,f10 # # Piece: King # Move: leap (0,1) # Symbol: "K", "K,k" # Flags: royal # Prison: white_palace, black_palace # Defines the XiangQi king, which is only allowed to move inside the palace. # DROPS # # For variants that include drops, the default rule is that pieces in-hand may be dropped anywhere on the # board, as long as pieces are allowed to move from their new location. You can override this: # Drop zone: all, all # allows pieces to be dropped everywhere, while # Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 # # Drop zone: rank1, rank8 # restricts drops to the (own) back rank. # Specifying the drop zone in this way implicitly sets the "drop_dead" piece property (see below). # PROMOTIONS # # Pieces promote as soon as they reach their promotion zone, to one of the possible promotion choices: # Promotion: rank8, rank1, "QRBN" # defines the promotion for a white pawn on rank 8 and for a black pawn on rank 1. # A promotion choice of "+" is treated in a special way: if the piece # symbol is "P" and it has promotion choice "+", then the piece will be # promoted to a piece with symbol "+P". It is your responsibility to make # sure that this piece is defined in the game! # If capture/drop rules are used, pieces that have a symbol that starts # with "+" will be demoted when captured. # Example: # Piece: Queen # Move: slide (D,A,H,V) # Symbol: "+P", "+P,+p" # # Piece: Pawn # Move: step N # Capture: step NE,NW # Special: rank2, rank7, step 2N # Symbol: " ", "P,p" # Flags: set_ep,take_ep # Promotion: rank8, rank1, "+" # # This example defines a Queen that will demote to Pawn when captured, and # a Pawn whose only promotion choice is the Queen (+P). # By default, promotion is mandatory if the piece has no legal moves from a given square, otherwise it is # optional. You can override this rule by specifying the optional promotion zone explicitly: # Optional promotion: empty, empty # makes all promotions for this piece type mandatory. # PIECE PROPERTIES # # Pieces can have a number of special properties, listed on a "Flags:" line. Multiple properties can be # specified in one line, separated by a comma. The following properties can be specified: # # royal This is a royal piece: the game is lost if a side were to lose all royal pieces. # set_ep This piece sets the "en-passant" capture square when it makes a special move. # take_ep This piece type can capture on the "en-passant" square. # drop_no_check This piece may not be dropped to give check. # drop_no_mate This piece may not be dropped to give mate (it may give check). # drop_one_file This piece may not be dropped on a file that already contains a friendly piece of the same type. # drop_dead This piece may be dropped even where it cannot move. # no_mate This piece may not deliver mate. It may deliver check. # shak This piece delivers a special "shak" check. # LIMIT THE NUMBER OF PIECES # # It is possible to limit the number of pieces of a particular type (by promotion) by specifying that number # in a "Max: number" or "Max: white,black" line: # Max: 2 # allows only two of this piece type for white and for black. You can set a different number for white and for # black. Pass 0 to leave this at the default (whch is 1 for royal pieces and unlimited for all other piece # types). # EXTRA RULES AND VICTORY CONDITIONS # # It's possible to specify a number of extra rule options or game-ending conditions. # End-of-game scores can be any of "win", "loss", "draw" or "illegal". # The following game-ending conditions can be defined: # # checkmate The enemy royal piece is under attack and cannot avoid being captured (win, loss or draw, normally win) # stalemate The enemy cannot make any legal moves (win, loss or draw, normally draw) # repeatN The game is declared a draw if a position occurs for the Nth time (win, loss or draw, normally draw and N = 3) # Set N=0 to disable any special treatment for repetitions. # perpetual As repeatN, but refers to in-check positions. If not specified defaults to "repeat" (win, loss, draw or repeat). # loneking Triggered if a side has a lone king remaining and baring rules are in effect (win, loss or draw, normally loss) # nopieces Triggered if the side-to-move has no pieces left (win, loss or draw, normally loss). # captureanyflag Triggered when capturing any flag (win, loss or draw, normally win). # captureallflags Triggered when capturing all flags (win, loss or draw, normally win). # # Examples (these are the defaults): # Rule: checkmate = win # Rule: stalemate = draw # Rule: repeat3 = draw # # The following special rules can be defined: # # taboo The kings may not share a ray with no pieces between them # keep capture Captured pieces are held in your hand (rather than just disappearing) # return capture Captured pieces are returned to their owner's hand # duplecheck If a side has more than one king, he is assumed to be in check if all of them are attacked. # Without this rule a side with more than one king can never be in check. # allow pickup As a move you can take one of your non-royal pieces from the board into your hand. # allow drops As a move you may place a piece from your hand on the board. # force drops If you have a piece in-hand you must place one on the board. # gate drops You may "gate" pieces from your hand when first moving a back-rank piece. # promote here A piece that is in the promomotion zone may promote without making a move. # promote drop A piece that is dropped in the promomotion zone may promote immediately. # special init Special moves are only allowed if the piece has not moved before. # bare rule If you have a bare king, you have one turn to bare your opponent's king in turn. # chase rule Xiangqi-style chases are not allowed. # shak rule Checkmate can only be given if a chain of checks leading to it contains at least one "shak" check. # PIECE NAMES AND SYMBOLS # # Pieces can be assigned names and symbols. # The piece name property is given on the "Piece:" line. It is an arbitrary # string with no special meaning; SjaakII uses this when asked to list the # rules and dump the internal board representation, but it is otherwise # purely cosmetic. # The piece symbol is set using the "Symbol:" property: # Symbol: "N", "N,n" # The first string ("N") is used for the output of moves in standard # algebraic notation (SAN), for instance "Nf3". The second string ("N,n") # identifies the symbol by which the piece is identified in a FEN string, # first for white and then for black. Normally, the black character is just # the lower case version of the white character, which is in upper case, # but Sjaak doesn't require this. The SAN character is normally the same as # the white symbol, but again this is not required. # There are two special symbols that have meaning when defining piece # symbols: # If a piece symbol starts with "+", say "+P", then this piece will demote to # "P" when captured, and a piece "P" will promote to this piece (if it has # promotion choice "+"). # If a piece symbol ends with "~", say "Q~", then this piece will demote to # whichever piece type promotes to "Q~". Make sure that there is a piece # type that lists "Q~" as a promotion option! # PIECE VISUALISATION (XBOARD/WINBOARD) # # You can specify the piece graphic that is used by XBoard/WinBoard to represent the pieces in your variant. # XBoard uses a string of 44 (2x22) characters in length. To use the N-th image you simply have to replace the # N-th character in the string with the symbol you assigned to the piece. The first 22 characters are for # white, the last 22 are for black. # The default value of the string is "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk", where the characters # represent the following pieces: # P=Pawn # N=Knight # B=Bishop # R=Rook # Q=Queen # F=Ferz # E=Alfil # A=Archbishop # C=Chancellor # W=Wazir # M=Man # O=Cannon # H=Nightrider # I=Dragon Horse # J=Dragon King # G=Grasshopper # D=Alternative Chancellor image # V=Falcon # L=Lance (or Amazon/Berolina pawn) # S=Snake # U=Unicorn # K=King # If you do not use a particular bitmap, simply put "." in its place. Example: # XBoard pieces: "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk" # When specifying the string, you can write both "XBoard" and "WinBoard". ############################################################# # Example: duplicate the definition for standard FIDE chess # ############################################################# Variant: FIDE Chess (8x8) # Name with which the variant can be selected Board: 8x8 # Board size FEN: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -" # Startup FEN, pieces defined below XBoard pieces: "PNBRQKpnbrqk" Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 # Special regions on the board, used below Zone: rank7 = a7,b7,c7,d7,e7,f7,g7,h7 Zone: rank2 = a2,b2,c2,d2,e2,f2,g2,h2 Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Castle: white e1-g1 with h1 Castle: white e1-c1 with a1 Castle: black e8-g8 with h8 Castle: black e8-c8 with a8 Piece: Pawn Move: step N Capture: step NE,NW Special: rank2, rank7, step 2N Symbol: " ", "P,p" Flags: set_ep,take_ep Promotion: rank8, rank1, "QRBN" Value: 100 Rule: checkmate = win Rule: stalemate = draw Rule: repeat3 = draw ############################################################################################ # Example: wolves and Sheep. The wolves try to corner the sheep, the sheep tries to escape # ############################################################################################ Variant: Wolves and Sheep (8x8) Board: 8x8 FEN: "1w1w1w1w/8/8/8/8/8/8/4S3 w - -" XBoard pieces: ".....W...S.................w...s............" BlackFlag: a8,b8,c8,d8,e8,f8,g8,h8 Piece: Sheep Move: leap (1,1) Capture: none Symbol: "S", "S,s" Piece: Wolf Move: aleap (1,1)|(-1,1) Capture: none Symbol: "W", "W,w" Rule: captureanyflag = win Rule: stalemate = win ########################### # Maharaja and the Sepoys # ########################### Variant: Maharaja Board: 8x8 FEN: "rnbqkbnr/pppppppp/8/8/8/8/8/4M3/ w KQkq -" XBoard pieces: ".........M............pnbrq................k" Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 Zone: rank7 = a7,b7,c7,d7,e7,f7,g7,h7 Zone: rank2 = a2,b2,c2,d2,e2,f2,g2,h2 Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 32 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 32 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 50 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 95 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Castle: black e8-g8 with h8 Castle: black e8-c8 with a8 Piece: Maharaja Move: slide (D,A,H,V) Move: leap (2,1) Symbol: "M", "M,m" Flags: royal Piece: Pawn Move: step N Capture: step NE,NW Special: rank2, rank7, step 2N Symbol: " ", "P,p" Flags: set_ep,take_ep Promotion: rank8, rank1, "QRBN" Value: 10 ###################################################### # Peasant Revolt (Pritchard 2007, chessvariants.org) # ###################################################### Variant: Peasant's Revolt (8x8) Board: 8x8 FEN: "1nn1k1n1/4p3/8/8/8/8/PPPPPPPP/4K3 w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 250 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step N Capture: step NE,NW Symbol: " ", "P,p" Promotion: rank8, rank1, "QRBN" Value: 100 ################################### # Corridor Chess (Pritchard 2007) # ################################### Variant: Corridor Chess (8x8) Board: 8x8 FEN: "1nrqkrn1/2b2b2/1pppppp1/8/8/1PPPPPP1/2B2B2/1NRQKRN1 w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step N Capture: step NE,NW Symbol: " ", "P,p" Promotion: rank8, rank1, "QRBN" Value: 100 ############################################################ # Legan's chess (http://en.wikipedia.org/wiki/Legan_chess) # ############################################################ Variant: Legan's Chess (8x8) Board: 8x8 FEN: "knbrp3/bqpp4/npp5/rp1p3P/p3P1PR/5PPN/4PPQB/3PRBNK w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: white_promo = a5,a6,a7,a8,b8,c8,d8 Zone: black_promo = e1,f1,g1,h1,h2,h3,h4 # Define the pieces Piece: Knight # New piece and its name Move: leap (2,1) # Movement type Symbol: "N", "N,n" # Symbol used for SAN and symbols used in FEN Value: 320 # Piece value, used by evaluation Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step NW Capture: step N,W Symbol: " ", "P,p" Promotion: white_promo, black_promo, "QRBN" Value: 100 ################################## # Diamond Chess (Pritchard 2007) # ################################## Variant: Diamond Chess (8x8) Board: 8x8 FEN: "krbp4/rqnp4/nbpp4/pppp4/4PPPP/4PPBN/4PNQR/4PBRK w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: white_promo = a1,a2,a3,a4,a5,a6,a7,a8,b8,c8,d8,e8,f8,g8,h8 Zone: black_promo = a1,b1,c1,d1,e1,f1,g1,h1,h2,h3,h4,h5,h6,h7,h8 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step NW Capture: step N,W Symbol: " ", "P,p" Promotion: white_promo, black_promo, "QRBN" Value: 100 ################################### # Diagonal Chess (Pritchard 2007) # ################################### Variant: Diagonal Chess (8x8) Board: 8x8 FEN: "4pnrk/4pbpr/4pbqn/4pppp/PPPP4/NQBP4/RPBP4/KRNP4 w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: white_promo = h1,h2,h3,h4,h5,h6,h7,a8,b8,c8,d8,e8,f8,g8,h8 Zone: black_promo = a1,b1,c1,d1,e1,f1,g1,h1,a2,a3,a4,a5,a6,a7,a8 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step NE Capture: step N,E Symbol: " ", "P,p" Promotion: white_promo, black_promo, "QRBN" Value: 100 ################################# # Corner Chess (Pritchard 2007) # ################################# Variant: Corner Chess (8x8) Board: 8x8 FEN: "kbp2pbq/nrp2prn/pp4pp/8/8/PP4PP/NRP2PRN/QBP2PBK w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: white_promo = a8,b8,c8,d8,e8,f8,g8,h8 Zone: black_promo = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step NE,NW Capture: step N Symbol: " ", "P,p" Promotion: white_promo, black_promo, "QRBN" Value: 100 ############################################################################ # A variant of Shatranj with dabbabah's, supposedly from 9th century India # ############################################################################ Variant: Ninth Century Indian Chess (8x8) Board: 8x8 FEN: "dnrkfrnd/pppppppp/8/8/8/8/PPPPPPPP/DNRKFRND w - -" XBoard pieces: "PN.R.F........D......Kpn.r.f........d......k" # Use the "crowned rook" for the dabbabah Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Dabbabah Move: leap (2,0) Symbol: "D", "D,d" Value: 200 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Ferz Move: leap (1,1) Symbol: "F", "F,f" Value: 150 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Piece: Pawn Move: step N Capture: step NE,NW Symbol: " ", "P,p" Promotion: rank8, rank1, "F" Value: 100 Rule: stalemate = win # The stale-mated player wins (!) Rule: loneking = loss ########################################################################### # Troitzky chess # # http://www.chessvariants.org/index/msdisplay.php?itemid=MPtroitzkychess # ########################################################################### Variant: Troitzky Chess (10x10) Board: 10x10 FEN: "****qk****/**rnbbnr**/*pppppppp*/*8*/10/10/*8*/*PPPPPPPP*/**RNBBNR**/****QK**** w - -" XBoard pieces: "PNBRQKpnbrqk" Zone: white_promotion = a6,b8,c9,d9,e10,f10,g9,h9,i8,j6 Zone: black_promotion = a5,b3,c2,d2,e1,f1,g2,h2,i3,j5 Zone: rank8 = b8,c8,d8,e8,f8,g8,h8,i8 Zone: rank3 = b3,c3,d3,e3,f3,g3,h3,i3 Exclude: a1,b1,c1,d1,g1,h1,i1,j1,a2,b2,i2,j2,a3,j3,a4,j4 Exclude: a10,b10,c10,d10,g10,h10,i10,j10,a9,b9,i9,j9,a8,j8,a7,j7 Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Castle: white f2-e1 with e1 Castle: white f2-f1 with f1 Castle: black f9-e10 with e10 Castle: black f9-f10 with f10 Piece: Pawn Move: step N Capture: step NE,NW Special: rank3, rank8, step 2N Symbol: " ", "P,p" Promotion: white_promotion, black_promotion, "QRBN" Value: 100 ########################################################################### # Troitzky chess, Byway setup # # http://www.chessvariants.org/index/msdisplay.php?itemid=MPtroitzkychess # ########################################################################### Variant: Troitzky Chess Byway (10x10) Board: 10x10 FEN: "****rr****/**nbqkbn**/*pppppppp*/*8*/10/10/*8*/*PPPPPPPP*/**NBQKBN**/****RR**** w KQkq -" XBoard pieces: "PNBRQKpnbrqk" Zone: white_promotion = a6,b8,c9,d9,e10,f10,g9,h9,i8,j6 Zone: black_promotion = a5,b3,c2,d2,e1,f1,g2,h2,i3,j5 Zone: rank8 = b8,c8,d8,e8,f8,g8,h8,i8 Zone: rank3 = b3,c3,d3,e3,f3,g3,h3,i3 Exclude: a1,b1,c1,d1,g1,h1,i1,j1,a2,b2,i2,j2,a3,j3,a4,j4 Exclude: a10,b10,c10,d10,g10,h10,i10,j10,a9,b9,i9,j9,a8,j8,a7,j7 Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Castle: white f2-e1 with e1 Castle: white f2-f1 with f1 Castle: black f9-e10 with e10 Castle: black f9-f10 with f10 Piece: Pawn Move: step N Capture: step NE,NW Special: rank3, rank8, step 2N Symbol: " ", "P,p" Promotion: white_promotion, black_promotion, "QRBN" Value: 100 ########################################## # Twilight Chess, with drops and pickups # ########################################## Variant: Twilight Chess (8x8) Board: 8x8 FEN: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -" XBoard pieces: "PNBRQKpnbrqk" Zone: rank8 = a8,b8,c8,d8,e8,f8,g8,h8 Zone: rank7 = a7,b7,c7,d7,e7,f7,g7,h7 Zone: rank2 = a2,b2,c2,d2,e2,f2,g2,h2 Zone: rank1 = a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 320 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 325 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 500 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Castle: white e1-g1 with h1 Castle: white e1-c1 with a1 Castle: black e8-g8 with h8 Castle: black e8-c8 with a8 Piece: Pawn Move: step N Capture: step NE,NW Special: rank2, rank7, step 2N Symbol: " ", "P,p" Flags: set_ep,take_ep Promotion: rank8, rank1, "QRBN" Value: 100 Rule: allow pickup, allow drops ################## # Judkins' Shogi # ################## Variant: Judkins' Shogi (6x6) Board: 6x6 FEN: "rbnsgk/5p/6/6/P5/KGSNBR" XBoard pieces: "PNBR.S...G.++++.+Kpnbr.s...g.++++.+k" XBoard parent: "shogi" Zone: white_promotion = a5,b5,c5,d5,e5,f5,a6,b6,c6,d6,e6,f6 Zone: black_promotion = a2,b2,c2,d2,e2,f2,a1,b1,c1,d1,e1,f1 # Define the pieces Piece: Knight Move: aleap (1,2)|(-1,2) Symbol: "N", "N,n" Promotion: white_promotion, black_promotion, "+" Value: 250 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Promotion: white_promotion, black_promotion, "+" Value: 575 Piece: Silver general Move: aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1) Symbol: "S", "S,s" Promotion: white_promotion, black_promotion, "+" Value: 375 Piece: Gold general Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "G", "G,g" Value: 450 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Promotion: white_promotion, black_promotion, "+" Value: 650 Piece: Pawn Move: step N Symbol: "P", "P,p" Promotion: white_promotion, black_promotion, "+" Flags: drop_no_mate, drop_one_file Value: 80 Piece: Promoted Knight Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+N", "+N,+n" Value: 500 Piece: Dragon Horse Move: slide (D,A) Move: leap (1, 0) Symbol: "+B", "+B,+b" Value: 825 Piece: Promoted Silver Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+S", "+S,+s" Value: 490 Piece: Dragon King Move: slide (H,V) Move: leap (1, 1) Symbol: "+R", "+R,+r" Value: 950 Piece: Promoted Pawn Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+P", "+P,+p" Value: 530 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Rule: keep capture, allow drops Rule: repeat4 = draw Rule: perpetual = illegal ################################################################### # Omicron chess: omega chess on a smaller board (2 ranks deleted) # ################################################################### Variant: Omicron Chess (12x10) Board: 12x10 FEN: "w**********w/*crnbqkbnrc*/*pppppppppp*/*10*/*10*/*10*/*10*/*PPPPPPPPPP*/*CRNBQKBNRC*/W**********W w KQkq -" XBoard pieces: "PNBRQ..C.W...........Kpnbrq..c.w...........k" Exclude: b1,c1,d1,e1,f1,g1,h1,i1,j1,k1 Exclude: b10,c10,d10,e10,f10,g10,h10,i10,j10,k10 Exclude: a2,a3,a4,a5,a6,a7,a8,a9 Exclude: l2,l3,l4,l5,l6,l7,l8,l9 Zone: white_promotion = b9,c9,d9,e9,f9,g9,h9,i9,j9,k9; Zone: black_promotion = b2,c2,d2,e2,f2,g2,h2,i2,j2,k2; Zone: rank3 = b3,c3,d3,e3,f3,g3,h3,i3,j3,k3; Zone: rank8 = b8,c8,d8,e8,f8,g8,h8,i8,j8,k8; # Define the pieces Piece: Knight Move: leap (2,1) Symbol: "N", "N,n" Value: 250 Piece: Champion Move: leap (0,1)|(0,2)|(2,2) Symbol: "C", "C,c" Value: 375 Piece: Wizard Move: leap (1,1)|(1,3) Symbol: "W", "W,w" Value: 350 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Value: 400 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Value: 600 Piece: Queen Move: slide (D,A,H,V) Symbol: "Q", "Q,q" Value: 950 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Castle: white g2-i2 with j2 Castle: white g2-e2 with c2 Castle: black g9-i9 with h9 Castle: black g9-e9 with j9 Piece: Pawn Move: step N Capture: step NE,NW Special: rank3, rank8, step 2N Symbol: " ", "P,p" Flags: set_ep,take_ep Promotion: white_promotion, black_promotion, "QRBNWC" Value: 100 ############# # EuroShogi # ############# Variant: EuroShogi (8x8) Board: 8x8 FEN: "1nbgkgn1/1r4b1/pppppppp/8/8/PPPPPPPP/1B4R1/1NGKGBN1[-] w 0 1" XBoard pieces: "PNBR.....G.++++Kpnbr.....g.++++k" XBoard parent: "shogi" Zone: white_promotion = a8,b8,c8,d8,e8,f8,g8,h8,a7,b7,c7,d7,e7,f7,g7,h7,a6,b6,c6,d6,e6,f6,g6,h6 Zone: black_promotion = a3,b3,c3,d3,e3,f3,g3,h3,a2,b2,c2,d2,e2,f2,g2,h2,a1,b1,c1,d1,e1,f1,g1,h1 # Define the pieces Piece: Knight Move: aleap (1,2)|(-1,2)|(1,0)|(-1,0) Symbol: "N", "N,n" Promotion: white_promotion, black_promotion, "+" Optional promotion: empty, empty Value: 250 Piece: Bishop Move: slide (D,A) Symbol: "B", "B,b" Promotion: white_promotion, black_promotion, "+" Optional promotion: empty, empty Value: 575 Piece: Gold general Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "G", "G,g" Value: 450 Piece: Rook Move: slide (H,V) Symbol: "R", "R,r" Promotion: white_promotion, black_promotion, "+" Optional promotion: empty, empty Value: 650 Piece: Pawn Move: step N Symbol: "P", "P,p" Promotion: white_promotion, black_promotion, "+" Optional promotion: empty, empty Flags: drop_no_mate, drop_one_file Value: 80 Piece: Promoted Knight Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+N", "+N,+n" Value: 500 Piece: Dragon Horse Move: slide (D,A) Move: leap (1, 0) Symbol: "+B", "+B,+b" Value: 825 Piece: Dragon King Move: slide (H,V) Move: leap (1, 1) Symbol: "+R", "+R,+r" Value: 950 Piece: Promoted Pawn Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+P", "+P,+p" Value: 530 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Rule: keep capture, allow drops Rule: repeat4 = draw ############# # YariShogi # ############# Variant: YariShogi (7x9) Board: 7x9 FEN: "rnnkbbr/7/ppppppp/7/7/7/PPPPPPP/7/RBBKNNR[-] w 0 1" XBoard pieces: "PNBR.......++++Kpnbr.......++++k" XBoard parent: "shogi" Zone: white_promotion = a9,b9,c9,d9,e9,f9,g9,a8,b8,c8,d8,e8,f8,g8,a7,b7,c7,d7,e7,f7,g7 Zone: black_promotion = a3,b3,c3,d3,e3,f3,g3,a2,b2,c2,d2,e2,f2,g2,a1,b1,c1,d1,e1,f1,g1 # Define the pieces Piece: YariKnight Move: aleap (1,2)|(-1,2) Move: step 9N Symbol: "N", "N,n" Promotion: white_promotion, black_promotion, "+" Value: 300 Piece: YariBishop Move: aleap (1,1)|(-1,1) Move: step 9N Symbol: "B", "B,b" Promotion: white_promotion, black_promotion, "+" Value: 400 Piece: YariRook Move: slide (H) Move: step 9N Symbol: "R", "R,r" Promotion: white_promotion, black_promotion, "+" Value: 550 Piece: Pawn Move: step N Symbol: "P", "P,p" Promotion: white_promotion, black_promotion, "+" Flags: drop_no_mate, drop_one_file Value: 80 Piece: YariSilver Move: aleap (0,1)|(1,1)|(-1,1) Move: step 9S Symbol: "+P", "+P,+p" Value: 375 Piece: YariGoldKnight Move: aleap (0,1)|(1,1)|(-1,1)|(0,1)|(0,-1) Move: step 9S Symbol: "+N", "+N,+n" Value: 425 Piece: YariGoldBishop Move: aleap (0,1)|(1,1)|(-1,1)|(0,1)|(0,-1) Move: step 9S Symbol: "+B", "+B,+b" Value: 425 Piece: Rook Move: slide (H,V) Symbol: "+R", "+R,+r" Value: 650 Piece: General Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Rule: keep capture, allow drops Rule: repeat4 = draw Rule: perpetual = loss ################# # Goro Goro Shogi # ################# Variant: GoroGoro Shogi (5x6) Board: 5x6 FEN: "sgkgs/5/1ppp1/1PPP1/5/SGKGS[-] w 0 1" XBoard pieces: "P....S...G.+....+Kp....s...g.+....+k" XBoard parent: "shogi" Zone: white_promotion = a5,b5,c5,d5,e5,a6,b6,c6,d6,e6 Zone: black_promotion = a2,b2,c2,d2,e2,a1,b1,c1,d1,e1 # Define the pieces Piece: Silver general Move: aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1) Symbol: "S", "S,s" Promotion: white_promotion, black_promotion, "+" Value: 375 Piece: Gold general Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "G", "G,g" Value: 450 Piece: Pawn Move: step N Symbol: "P", "P,p" Promotion: white_promotion, black_promotion, "+" Flags: drop_no_mate, drop_one_file Value: 80 Piece: Promoted Silver Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+S", "+S,+s" Value: 490 Piece: Promoted Pawn Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+P", "+P,+p" Value: 530 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Rule: keep capture, allow drops Rule: repeat4 = draw Rule: perpetual = loss ####################################### # Goro Goro Shogi Knight & Lance Drop # ####################################### Variant: GoroGoroNL Shogi (5x6) Board: 5x6 FEN: "sgkgs/5/1ppp1/1PPP1/5/SGKGS[NLnl] w 0 1" XBoard pieces: "PN..LS...G.++..++Kpn..ls...g.++..++k" XBoard parent: "shogi" Zone: white_promotion = a5,b5,c5,d5,e5,a6,b6,c6,d6,e6 Zone: black_promotion = a2,b2,c2,d2,e2,a1,b1,c1,d1,e1 # Define the pieces Piece: Silver general Move: aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1) Symbol: "S", "S,s" Promotion: white_promotion, black_promotion, "+" Value: 375 Piece: Gold general Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "G", "G,g" Value: 450 Piece: Pawn Move: step N Symbol: "P", "P,p" Promotion: white_promotion, black_promotion, "+" Flags: drop_no_mate, drop_one_file Value: 80 Piece: Knight Move: aleap (1,2)|(-1,2) Symbol: "N", "N,n" Promotion: white_promotion, black_promotion, "+" Value: 250 Piece: Lance Move: step 5N Symbol: "L", "L,l" Promotion: white_promotion, black_promotion, "+" Value: 250 Piece: Promoted Silver Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+S", "+S,+s" Value: 490 Piece: Promoted Pawn Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+P", "+P,+p" Value: 530 Piece: Promoted Knight Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+N", "+N,+n" Value: 500 Piece: Promoted Lance Move: aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1) Symbol: "+L", "+L,+l" Value: 480 Piece: King Move: leap (0,1)|(1,1) Symbol: "K", "K,k" Flags: royal Rule: keep capture, allow drops Rule: repeat4 = draw Rule: perpetual = loss SjaakII/CMakeLists.txt000644 000765 000024 00000025723 12500130651 015631 0ustar00eglebbkstaff000000 000000 cmake_minimum_required(VERSION 2.4 FATAL_ERROR) # Set build type. Do this *before* we set the project name if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo Profile." FORCE) endif(NOT CMAKE_BUILD_TYPE) set(CMAKE_CONFIGURATION_TYPES "${CMAKE_BUILD_TYPE}" CACHE INTERNAL "internal") if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) project(sjaakxx CXX C) # Search in the `cmake' directory for additional CMake modules. list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) # Declare program options option(WANT_WARN "Generate compiler warnings" on) option(WANT_WERROR "Treat warnings as errors" off) option(WANT_NATIVE "Optimise for the current machine" off) option(WANT_ASSERT "Enable assertions in the code (for debugging)" off) option(WANT_OPT "Standard optimisations on/off" on) option(WANT_POPCNT "Use POPCNT instruction" off) option(WANT_SSE42 "Switch on SSE 4.2" on) option(WANT_SSE3 "Switch on SSE 3" off) option(WANT_SSE2 "Switch on SSE 2" off) option(WANT_32BIT "Force compiler to generate 32 bit code" off) option(WANT_64BIT "Force compiler to generate 64 bit code" off) #option(WANT_GUI "Wether you want to build the GUI or not (requires Allegro)" off) #option(WANT_MGUI "Wether you want to build the mobile GUI or not (requires Allegro) (experimental)" off) option(WANT_STATIC "Wether you want to static link to standard libraries" off) option(WANT_PROFILE_GENERATE "Generate executable suitable for running profile-guided optimisation" off) option(WANT_PROFILE_USE "Generate executable using data from profile-generate run" off) option(WANT_PROFILE "Generate executable suitable for running with gprof" off) option(WANT_RELEASE "Generate a binary with a mangled name to represent the current platform" off) set(SJAAKII_DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/games/sjaakii/" CACHE STRING "Install location for data files (${CMAKE_INSTALL_PREFIX}/share/games/sjaakii/)") # Parse user options if(WANT_OPT) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -finline") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O3 -finline") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -finline") endif(WANT_OPT) if(WANT_WARN) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wall -Wextra -Wno-unused") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused") endif(WANT_WARN) if(WANT_WERROR) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-unused -Werror") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wall -Wno-unused -Werror") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused -Werror") endif(WANT_WERROR) if(WANT_NATIVE) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mtune=native") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -march=native -mtune=native") endif(WANT_NATIVE) if(WANT_POPCNT) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mpopcnt") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mpopcnt") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt") endif(WANT_POPCNT) if(WANT_SSE42) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.2") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -msse4.2") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2") endif(WANT_SSE42) if(WANT_SSE3) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -msse3") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse3") endif(WANT_SSE3) if(WANT_SSE2) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -msse2") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2") endif(WANT_SSE2) if(WANT_PROFILE_GENERATE) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-generate") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-generate") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate") endif(WANT_PROFILE_GENERATE) if(WANT_PROFILE_USE) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-use") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-use") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use") endif(WANT_PROFILE_USE) if(WANT_ASSERT) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUGMODE") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -DDEBUGMODE") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUGMODE") endif(WANT_ASSERT) if(WANT_32BIT) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") endif(WANT_32BIT) if(WANT_PROFILE) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg -g") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg -g") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -g") endif(WANT_PROFILE) if(WANT_64BIT) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m64") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64") endif(WANT_64BIT) if(WANT_STATIC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") endif(WANT_STATIC) # Search for C header files in these directories. include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include ) set (SJAAKIIVERSION "\"1.0 RC7\"") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSJAAKIIVERSION=\\\"${SJAAKIIVERSION}\\\"") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSJAAKIIVERSION=\\\"${SJAAKIIVERSION}\\\"") if(WANT_GUI) set(WANT_ALLEGRO 1) endif(WANT_GUI) if(WANT_MGUI) set(WANT_ALLEGRO 1) endif(WANT_MGUI) if(WANT_ALLEGRO) # Find zlib find_package(ZLIB) if (ZLIB_FOUND) list(APPEND GUI_LIBS ${ZLIB_LIBRARIES}) include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS}) else (ZLIB_FOUND) message(FATAL_ERROR "Can't find zlib library") endif(ZLIB_FOUND) # Find Allegro set(ALLEGRO5_VERSION "5.1") find_package(Allegro5) if (ALLEGRO5_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5_INCLUDE_DIRS}) else (ALLEGRO5_FOUND) message(FATAL_ERROR "Can't find Allegro library") endif(ALLEGRO5_FOUND) # Find Allegro addons find_package(Allegro5Main) if (ALLEGRO5MAIN_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5MAIN_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5MAIN_INCLUDE_DIRS}) else (ALLEGRO5MAIN_FOUND) message(FATAL_ERROR "Can't find Allegro main addon") endif(ALLEGRO5MAIN_FOUND) find_package(Allegro5Primitives) if (ALLEGRO5PRIMITIVES_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5PRIMITIVES_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5PRIMITIVES_INCLUDE_DIRS}) else (ALLEGRO5PRIMITIVES_FOUND) message(FATAL_ERROR "Can't find Allegro Primitives addon") endif(ALLEGRO5PRIMITIVES_FOUND) find_package(Allegro5Font) if (ALLEGRO5FONT_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5FONT_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5FONT_INCLUDE_DIRS}) else (ALLEGRO5FONT_FOUND) message(FATAL_ERROR "Can't find Allegro font addon") endif(ALLEGRO5FONT_FOUND) find_package(Allegro5TTF) if (ALLEGRO5TTF_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5TTF_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5TTF_INCLUDE_DIRS}) else (ALLEGRO5TTF_FOUND) message(FATAL_ERROR "Can't find Allegro TTF addon") endif(ALLEGRO5TTF_FOUND) find_package(Allegro5Image) if (ALLEGRO5IMAGE_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5IMAGE_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5IMAGE_INCLUDE_DIRS}) else (ALLEGRO5IMAGE_FOUND) message(FATAL_ERROR "Can't find Allegro image addon") endif(ALLEGRO5IMAGE_FOUND) find_package(Allegro5Dialog) if (ALLEGRO5DIALOG_FOUND) list(APPEND GUI_LIBS ${ALLEGRO5DIALOG_LIBRARIES}) include_directories(SYSTEM ${ALLEGRO5DIALOG_INCLUDE_DIRS}) else (ALLEGRO5DIALOG_FOUND) message(FATAL_ERROR "Can't find Allegro DIALOG addon") endif(ALLEGRO5DIALOG_FOUND) endif(WANT_ALLEGRO) # Set install directory if (NOT SJAAKII_DATA_DIR) set(SJAAKII_DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/games/sjaakii/") endif (NOT SJAAKII_DATA_DIR) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDATADIR=\\\"${SJAAKII_DATA_DIR}\\\"") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDATADIR=\\\"${SJAAKII_DATA_DIR}\\\"") # code source files include(FileList) # Make a link library out of the source files add_library ("libsjaak" STATIC ${SJAAK_SRC_FILES}) # Look for the standard math library find_library(M_LIB m) target_link_libraries("libsjaak" ${M_LIB}) # Look for the standard math library include(CheckLibraryExists) CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) if (HAVE_CLOCK_GETTIME) target_link_libraries("libsjaak" rt) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_CLOCK_GETTIME") endif (HAVE_CLOCK_GETTIME) add_executable ("sjaakii" src/xboard.cc) target_link_libraries("sjaakii" libsjaak) add_custom_command(TARGET "sjaakii" POST_BUILD COMMAND pod2man -s 6 ${CMAKE_SOURCE_DIR}/sjaakii.pod | gzip > ${CMAKE_BINARY_DIR}/sjaakii.6.gz ) # Find readline find_package(Readline) if (READLINE_FOUND) target_link_libraries("sjaakii" ${READLINE_LIBRARY}) include_directories(SYSTEM ${READLINE_INCLUDE_DIRS}) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_READLINE") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_READLINE") else (READLINE_FOUND) message(WARNING "Can't find readline library - disabling support") endif(READLINE_FOUND) if(WANT_RELEASE) set(PLATF "-unknown") if(CMAKE_SYSTEM_NAME MATCHES "Windows") set(PLATF "-win") endif(CMAKE_SYSTEM_NAME MATCHES "Windows") if(CMAKE_SYSTEM_NAME MATCHES "Linux") set(PLATF "-linux") endif(CMAKE_SYSTEM_NAME MATCHES "Linux") if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(PLATF "-mac") endif(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(SSE "-sse") if(WANT_SSE2) set(SSE "-sse2") endif(WANT_SSE2) if(WANT_SSE3) set(SSE "-sse3") endif(WANT_SSE3) if(WANT_SSE42) set(SSE "-sse42") endif(WANT_SSE42) set(POPCNT "") if(WANT_POPCNT) set(POPCNT "-popcnt") endif(WANT_POPCNT) set(BITS "") if(WANT_64BIT) set(BITS "64") endif(WANT_64BIT) if(WANT_32BIT) set(BITS "32") endif(WANT_32BIT) set(VERSION "-${Project_WC_REVISION}") set(RELEASE_NAME "sjaakii${VERSION}${PLATF}${BITS}${SSE}${POPCNT}") set_target_properties(sjaakii PROPERTIES OUTPUT_NAME "${RELEASE_NAME}") endif(WANT_RELEASE) # Installation targets install (TARGETS "sjaakii" RUNTIME DESTINATION "bin") install (FILES "${CMAKE_BINARY_DIR}/sjaakii.6.gz" DESTINATION "share/man/man6") install (FILES "${CMAKE_SOURCE_DIR}/variants.txt" DESTINATION "share/games/sjaakii/") install (FILES "${CMAKE_SOURCE_DIR}/misc/sjaakii.eng" DESTINATION "share/games/plugins/xboard/") install (FILES "${CMAKE_SOURCE_DIR}/misc/sjaakii.png" DESTINATION "share/games/plugins/logos/") SjaakII/MSVS2012/SjaakII.sln000644 000765 000024 00000003224 12452237254 016164 0ustar00eglebbkstaff000000 000000  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SjaakII", "SjaakII.vcxproj", "{33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release Intel|Win32 = Release Intel|Win32 Release Intel|x64 = Release Intel|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Debug|Win32.ActiveCfg = Debug|Win32 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Debug|Win32.Build.0 = Debug|Win32 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Debug|x64.ActiveCfg = Debug|x64 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Debug|x64.Build.0 = Debug|x64 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release Intel|Win32.ActiveCfg = Release Intel|Win32 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release Intel|Win32.Build.0 = Release Intel|Win32 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release Intel|x64.ActiveCfg = Release Intel|x64 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release Intel|x64.Build.0 = Release Intel|x64 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release|Win32.ActiveCfg = Release|Win32 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release|Win32.Build.0 = Release|Win32 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release|x64.ActiveCfg = Release|x64 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal SjaakII/MSVS2012/SjaakII.vcxproj000644 000765 000024 00000033735 12502303035 017060 0ustar00eglebbkstaff000000 000000  Debug Win32 Debug x64 Release Intel Win32 Release Intel x64 Release Win32 Release x64 {33B8E0A6-E08B-4F2C-9BE0-615DAA4436F7} Win32Proj SjaakII Application true v110 Unicode Application true v110 Unicode Application false v110_xp true MultiByte Application false Intel C++ Compiler XE 15.0 true MultiByte Application false v110_xp true MultiByte Application false Intel C++ Compiler XE 15.0 true MultiByte true true false false false false Level3 Disabled SJAAKIIVERSION="1.0.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\include;%(AdditionalIncludeDirectories) Console true Level3 Disabled SJAAKIIVERSION="1.0.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\include;%(AdditionalIncludeDirectories) Console true Level3 Full true true SJAAKIIVERSION="1.0.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\include;%(AdditionalIncludeDirectories) AnySuitable Speed true false MultiThreaded false Console true true true /SUBSYSTEM:CONSOLE,"5.01" %(AdditionalOptions) Level3 Full true true SJAAKIIVERSION="1.0.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\include;%(AdditionalIncludeDirectories) OnlyExplicitInline Speed true false MultiThreaded false /Qopt-report-embed- %(AdditionalOptions) false Console false true true /SUBSYSTEM:CONSOLE,"5.01" %(AdditionalOptions) Level3 Full true true SJAAKIIVERSION="1.0.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\include;%(AdditionalIncludeDirectories) AnySuitable Speed true false MultiThreaded false Console true true true /SUBSYSTEM:CONSOLE,"5.02" %(AdditionalOptions) Level3 Full true true SJAAKIIVERSION="1.0.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\include;%(AdditionalIncludeDirectories) OnlyExplicitInline Speed true false MultiThreaded false /Qopt-report-embed- %(AdditionalOptions) false Console false true true /SUBSYSTEM:CONSOLE,"5.02" %(AdditionalOptions) SjaakII/MSVS2012/SjaakII.vcxproj.filters000644 000765 000024 00000002027 12452237254 020532 0ustar00eglebbkstaff000000 000000  SjaakII/sjaakii.pod000644 000765 000024 00000004715 12470157255 015225 0ustar00eglebbkstaff000000 000000 =head1 NAME sjaakii - xboard-compatible chess and chess-variant engine 'SjaakII' =head1 SYNOPSIS B [-log|-newlog [filename]] [-variant name] [-no_user_variants] [-xboard|-uci|-uci|-ucci] [variant file] =head1 DESCRIPTION B is a program that plays chess and chess variants. It uses the xboard/winboard chess-engine protocol to communicate. Apart from normal chess, SjaakII can play Seirawan Chess, Mongolian Shatar, Makruk (including variants ASEAN and Ai-Wok), Shatranj, Sittuyin (Burmese Chess), Crazy House Chess, Chessgi, Spartan Chess, Pocket Knight Chess, King-of-th-Hill, Knightmate, Amazon Chess, Chancellor Chess, Berolina Chess, Los Alamos Chess, Micro Chess, Capablanca Chess, Gothic Chess, Embassy Chess, Courier Chess, Grand Chess, Opulent Chess, Omega Chess, Shogi (including variants Mini Shogi, Sho Shogi and Tori Shogi) and Xiang-Qi. Other variants can be added through a configuration file. See xboard(6) for instructions about how to use B through xboard. To start up quickly, you just need the command: B. Some of the variants SjaakII plays are only partially supported by XBoard, and can only be played whith the legality-testing function of the latter switched off. =head1 OPTIONS =over 8 =item B<-log [filename]> Append all communication by SjaakII and XBoard to a logfile. If no filename is specified, the log is written to sjaakii.log. =item B<-newlog [filename]> As B<-log>, but the file is overwritten rather than added to. =item B<-variant name> Normally, SjaakII starts with variant "normal" (regular chess), but it can be made to start with any other named variant with this option. =item B<-no_user_variants> Do not read the default variant configuration file. You can still specify a file in the engine options. =item B<-xboard> Start in xboard mode rather than the default mode. =item B<-uci> Start in UCI mode rather than the default mode. =item B<-usi> Start in USI mode rather than the default mode. =item B<-ucci> Start in UCCI mode rather than the default mode. =item B Read variant descriptions from the named file. =back =head1 AVAILABILITY From http://www.eglebbk.dds.nl/program/chess-index.html =head1 SEE ALSO xboard(6) =head1 STANDARDS WinBoard, B(6) interface ("Chess Engine Communication Protocol") =head1 AUTHOR Evert Glebbeek . This manual page was based on the man page for Fairy-Max by H.G. Muller and was generated with pod2man(1). SjaakII/misc/sjaakii.png000644 000765 000024 00000026344 12433414314 016153 0ustar00eglebbkstaff000000 000000 ‰PNG  IHDR‚A|çbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ /×¶†iTXtCommentCreated with GIMPd.e IDATxÚÕwxUö3»›NB „Þ”&UšØPAP¤J—^^z¤ /E@AŠ©"¨( UB - éewf¾?fgvfw6Ñ÷»¾ï\×\›Ý3sæœûÜçyîç9!t×CIïÒŽÐ]ðµør~z—v¦÷Š¢x® ¦÷î×~صŒõ•ƒkù·‹Ðv€Ç½ÝÛìÞ¦°°0îÜÙ@ppS¶´ø×ÚôÊá\²²Nü£ëŠî„î:àÑÙÿK<¬õ‹ ã ý[ 0‚K»Ÿ·vôïßI’HKK#==àà¦> Ö+‡s‹Ô®-­þ1¸Doú†¾€¡8Lðo‚Á_À°~ýzÖ¯_@BB‚þy©R¥|AQÀðÊá\~ü<¸È2=ŸûÒàË`¾”‡±Eq—÷™üO™ (ËDéÒ¥©T©GÅßßAˆ‰‰an¥{>1/ìñãçÁúû=³ŠÅ ba_zc†â€Àjµ²aÃΟ?Ï¢E‹ˆŽŽæÐ¡Cœ?žÞ½{û¼L×&ø'ÌPˆÜ™aĈ<ûì³lÛ¶¤¤$E!11QÀöíÛ¹~ý:ãÊú´6ËÝA› eo[T|òÉ'ôíÛ—°°0öíÛG“&MHKK#,,Œ3f0yòä"3ƒ·ÙçËŒ/*3øz¾7f(¨H’DÆ ¹~ý:¥J•bvùÛ§(ŠÇ3»Ïro 0–¢2ƒøoS…­ãiiiôéÓ‡íÛ·ÆöíÛM عs±ÏÌ B±¼ƒ¢0CQ@£ÛÎvΙ3‡±cÇz=×b±pøða5jă¼‚ÀÛ3Ï{ŠÃ âÿ hkåöíÛéÞ½;wïÞ¥{÷î,^¼ØtΞ=ËŠ´LÇEô Ee޼|»éý­[·˜7o^燅…ñÅ_’’Rè3zƒ/ (D_8t×ýðf> V«•Ù³g“‘‘ÁÔ©S©S§{öì¡iÓ¦´mÛ䃡ÈFi!`(Ža¹j÷AŽ;¦¿_ºtéCÛZ²dI6mÚôp ÿÃgö ¯Îýç^CQu÷¤®cŸ}6‹Å…Ë^â»ÍPLÀC(NÇßäÑ7¦kÀ6›äädJ–,iz¾‡=³¯¬ð0›Ac±8:Æ ÞØ!00–-[²`ÁSã[·n¬ÿݱcGºuëÀðá}غu‹È™3—X°`=}ûŽ÷è‡ÃQ00Šé™¡8 HÍÈâƒ5_’™™Y¬û[­VŽ=Zdm¥CϬÌ ÆeÆ+#ÇEüþûï©U«‡ƒóçÏÓ©S'ý»gÓ¯ßDdY!""‚äädDQ¤råÊ”)S‚7Þx‘åË·81ŽfÍšÎÕ«WÙºu+Ë–-Ó-nQÿçÌP”z¿ÿþ;5*6uoß¾—^zÉä)T­šE||°OlX\fp·5ÄK1lРdÓ¦M¤¤¤pýúuRSS1bÆÍA–ÕJOOçÔ©S\ºt‰¤¤$Μù›¹s×±|ùZNŸ¾D­Zµ8pà7n$++‹Å‹³gÏÝâ.t*3h (Nݘ2%ùì³ÏþÑ^¹reÓW­šezý_1ƒ;€¬ÿ¾ûî;zõêŃ\Ež{î9æÍ›Ç+¯¼B«V­p8H’D£Fôu°iÓz<ø+»ví¢víÚ\¸pÁtýæÍ›óí·ß2hÐ V­Zå±~ºûÜE™Ýî²qQ™Áî¸uë–çu&5+“ž•CÏö1cãŸÔTmðïããƒúÌzfÑí9×PîçïqŸoöÛiÓÌJ—þÙli@‡žY&0èKCq—ƒ-ZPµjU’’’¼ÖñóócÊ”)ܹsG§x­øûû3eÊÛ=z™¯¿þºÀû8W_}•öíÛÿkda²qQ€tèÐ!Z·n €,ËX,&ö}ž‰};aµˆøuT¨!¹k×.ºvíj,g•µ‡ÌÌídgïE2Ľ-s4ŽiUÚB£’"ý~ÎÓÏÿIì zõê;v¬@äçç3qâDîݻǨQ£ˆˆˆà‘Gaùòå¬_ÿm¡ ؽ{75kÖôImôe™x˜lìë2qnà ڴiCBBñññX,~X8Š™ov#Ðß¿ƒz®]»R¥Ê}Óg))ÓILHNÎQ¬Ö …ü°aÃPEQ6lX¡÷*$ð×™%íìIpèÌ w9Àn·{¥FoeÛ¶m<ú裼ð ”)S†Ù³g³gÏ.]ºôꉉ‰dffb±ˆìÚµäÁ—ï+jW.Çœ·ºS·fuªU«ÆõÏçñd“:>Û+ZûEÑ»œž~›Áƒ»j3øj ¼?kIÒ=¤ë=³‹JnÒ¤ çÎÓ‡•Ž;’››Kzz:GeäÈ‘ 6LgˆB‘\¾<ׯ_§råòˆ¢X$ÑÉ8 E•}̱½Ÿ#=;åàZ*•)iºçüQè²ö^¡× ñ°|ƒÑ€t×J”(áqþ–Ö*#G6îÞ½»®†††Ú°àà`¦OŸÎœ9sxõÕWéܹ3ãÆcîܹ…J±Zyê©§øá‡xì±zÅR …¶Šå"GŽÖÎ_´h 4(°Þ¥K—ÈÏ?ïa Tâãƒu—ÒW0h€ðEf¶jâPQSÂFŒAtt4sçÎ¥oß¾,_¾¼À›Œ=š¥K—2tèPFŽIBB¿üò‹.µ6lØ?þø£Àúo¾ù&;?ϼy#=ähM|˜eýOåh_ K#hªT©RèuçÏŸONξ‡Þ¿mÛ¶…JÍmÚ´Ñ¿3þí­4hÐÀÔ2žëÕkðc%£¨3`ÀfΜI­ZµHKKóªž8q‚.]ºð×_‘——Ghh(©©©\¸pñãÇ3hÐ ú÷ïïµñ½zõ¢E‹|õÕÞ{ïU¯çü¿ G»3G`` AAA«’©©”.ý !!]=¾KNMZÚ dYæQDQ¤[E‘16OA© ÙX–åAðå—‹9uêçÎcþüùЧO:ÄÊ•+q84kÖŒ5jФIê֭˸qã8~ü8¡¡¡lÞ¼™† zf&NœÈ¬YÓèÛ÷…̸LøùùýcÑI¾ñ¬Q_QÚ@>°¦ÀkÆÅÅ‘””DrrrÇ… ÈË;EBB›BìqxºQböwM@ÓüwïV#lW¯ÞfåÊìß¿ŸiÓ¦±jÕ**V¬ÈÚµk9räË—/çþýûX,^{í5&NœHll,ß|ó Ó¦Mã×_UýÛÆ™:u*çÎc„ ˆ¢ÈÞ½{Ù°aK:]»>ñÐÔ˜!((ˆ¬¬¬"3ƒ/#±Ý›&ˆíÞô¸Odd¤o±ŠTYN¥t鄆¾¦·!-m÷ïr‚!Šààéßß¿Ðv>lt8¬[¹‚\ç¾]ÝJ›23¼ŒF(ŠBXX˜\Ù¹s‰Û¹˜5kß}÷Ó§O§]»vŒ?^w - Ÿ}ö=zôðh\¿~ýL2í믿N›6m --W1a›>¯÷"##¹ÿ¾O`ð5r¨Àøª•R¥JÑ¡CV¬Xá3._¾ÌO|ø0§OŸöø|CK· “$I&)&&Æ‚8ºuÎöíq¦s5êÕ«Àš5kx饗HLLä¹çž£OŸ><ûì³’’Bnn.aaa„‡‡såÊvîÜÉÊ•+¹zõ*/¼ðõêÕcÊ” DEEË |á…!ºkyçÎ*W®Ìµk× t-Åvo"ý´ÚÅ v¿ƒÈÛ· Ùù¹ÿ“ƒÜüûxªV­ª kZúYddX¡mLIIC# }™ê Ѐúõë3gΜBm÷|ÎÑ£GsúôiÒÓÓMzÏë?çñq Å#bccõ™ôÅ‹$…mÛѽû>ÿ|a¡©æ­Zµ"&&†ãÇÂgŸ}ÆÂ… 9sæ ùùù¦uµyóæ¼øâ‹œ'ôkfddèE‘€€gè˜ÇŒ, ZÛT0dèLдÞ^ªT8Gë†{©SíO¯ÏýçÙ`láOQ·Ñ³XJ´ÓÛ"g@É¿ˆœ±%×{Ý”Ì*¬Þ|ó—eœPÇQ$IÑ Äš5kÒ 6—…Ò¹u×÷4¥v£¦”-¤Û7®§óǯ·‰°üʰ7n¬>Ì팆ø«&,AÌöÃoÛC)©nMN±Ð¤{úCÑSŽÅ‹ÇéVza€èÜù=vï^úÐkÁpñâEžõr ‰) ­—à•Nö’’bgÂÃÃjà!u½u¡ ö´WRCšaI…<ƨʓ-M¦? gÇ¡—øpÅáI„";î †lsèàÔÅj·ß Z¨^½º‹µÕ¬Y)'™9£3Ô°ñtx¡=eË!Ë ’$#IåÊñ|×jÔlÙ•ÁS›™-è~V@€?‹wóÁØ'¾Ú}ׯßVM6EÑ8ov‰¯ ôöåË—©Q£†~=Y–Y±)ƒ¯H,X÷ Àú÷îÝÃápèî^tt4V«•»w÷#Ë2²¬èö‡»"[\ï 9ãÊ•0ç3«vAü• <ÙÃ3†³`uZ<^—üü|Ãáp`·ÛqH rØpº×Ò{awHäççsþüy3ªW¯ÎÕ«Wyëå`üý®ÝôçÑæ ‘$‡CB’$óæÇ³Ýš1ki¬ÓÀ‚°°úVpSÐižÈýT ÷S-Œ™gy耕)S’uëfеë0}íÔ!ËŠÞá;¿Ç®]K<:׫D,«õ51,>>žš5kê&Ë2¤šÈÊuÍ„„ìv;’¤ö‡æ%\½ús’Ȧû¸ßÿaî#@ZÚÏ\¹(\½Z†›7@¶–÷8ÿêüü-äççc·ÛÕwÔø·CŒñ¨;bÌbS½³gϪ@ˆÕ]«¶ÍT‹>Àl6Y–M`$YG»,ËD– ƒG¸–àÏÁƒ¿"Ë2«WOUÝ,—$ºÿ—4î–NãnéüøKj¡RµjE&O~›°°v숣k×aÎŽ5[Õ]º eçÎÅúwfà1ƺ_~©ŠbW®\¡zõê&0$%¥xÀ ¦RŒÎv»ÚµkcµZÉÌÌ4õ‰ñoíþîºLက””#\½ZšÛ·÷RO@rHú`Á U’$¯A«!¡<ùä“`oÞTEŒçP¦¤ „rÑyØ3þÖ— FfÐÞ7nÅ7?EÒ¦McT7z¬^=•éÓß-’ïïïoãå—ŸeæÌ÷(]:RÔíÛãxñÅa(Š«“»vÆŽü~ï‡;@ÔCuÉvìˆàÆT«VÍpeêÆu½Ó{ì1, !!¿O… OšúC»‡k©À'fо‹Œ|œ*U)Wî ù¼Y–MË”û¡Ó“m¶áˆ¢HçÎMuEM'ðó³žér¥êEíFRtÚ3ÞÀø Qeùù¤?Š+WNâ­·¦¡( cÇÆ±fÍ4&MT À"б±èÕ«#K—N K—öÎN‘ ³TÕ/ºu$)të6‚/¾XäìXÙ÷CûÞ¸n«öŽ¢ë"·oß&44´@ €šŸÙºukDQ$0p?Šâ$bbâ©Xñ)g§Ê†IãÉCxxK=±rå[T®üLç«“Ò“Œ äÕFAÆfÛ„ tíÚU¯'ìØ§H’B#Ùº¸2Íq¹v©i~œºûéù•LW-SU†Ec®R»Âv"kŒAÞ~{†¾D 8•µk§;Ý®l¶m 3CA,݃Ÿ~¯êimK´ª}‚vU?!*ð/$}ÔÁ|ï½ÿ°téxPïÌ@’$†¾Q™CÇ’9u¾TˆÖ®‘xûÏ5=‚Í Çþz”¬ÀWq·ã¥A'ø3áIDºµûƒë—.²qãlz÷g²]D%Ø;±XVl(Ç¥û ­Ü‘ÖÎüÚQ„‰CnpáÔNÿy>}ƱqãlÝ&e™õëgØm¿þú+‡“ÙòµC_fd>þ<ŠgúufÕŽµ|}d$%Â/R¹ò3Î~1žšˆÊ,PÔð²1Æà~<¤¶s,6#vï>€Í›çѧÏxDaÝØs¬-÷Slž1ˆ\ÚÖ=B«Ê› ÷¿,ËŒ1¸¸1(ŠÂàÁ³X¾|"ï¾;Gø‹4vÃg%›Ön£¯Â/çg‚*e~` $Iâµ×&°nÝ 2•†¤gY±ÙB”ãØíÖ­›Ák¯MÐ-ö2¿c³ª2ö¶¯KÓ q””»õÈ—ü±Ù^î”HÜ‚X·n†î«Æ—Êšm£“$½Í’$qìØ1Þà‡Õ"™-ðö„ê,úøüJ¼‹(Šâ &Æ£°dœµ¡¡-LL`ƒàå³¢£ÈyŒª¥¢çÓOçЯß‚€5¢1‡¯÷gï±Xòíž/•ÁSõ¿! cq ßÕ— u™PX¾|¢Þïèáú¸{þj§?Ȱ !ôï?‰Õ«§ª3^VHNU×íŠQ): ¬^=•~ý>ÀáP퉔4 ¶€p¬VtØ29ùª\¿V&¡!eõkhƒml‹7•$‰€¼­¼ò¼Œ,£kòÓq‰ŒÜUNI]BQìN0HÄÄüíƒìᆅµ$66ݧÙZð·‚ŠÆæïD£Õ-êö7ßœ‚( Xý‚ÈzŽí¿tçÈïeðæY½Ð^¡U•mZS¼ˆ*š—a-Nê †}¶å×›=ysà4V­š¢§FGÕ†—ŒÈ#7×®ÏæU«¦0`Àd.'·àÔíŽì;Ó•÷Þo¨ÛÚ«â|ð¨Rv²2íäæÚuêÖA0χL¸u‹ ûgD(«ÉÈ´ÒT-Nž³cç/@!!¡¥ÓÒ—œV¿*ÇÄÄS©ÒÓ&+"¢•Ó0ôi~ûÌÅc‰&Œ9/¶nÝ  šît}ü‚£¸-wå“}ÏòëiÏIQÙ4©øÈy0(P(†\¼7é×黋þäû7bàà5|ôÑ$“Z—ñ ›E»"Ãd¤ç›D®>šÄ€³¹›Y—°¨*Y k´ rI÷nëõÒÓòõú1‚Åi‘y=‘e=i™VúލX—ÝßÎw“ [êPƒFŠS¸Nùòœ¡ö6ÄÆ¦ðo÷Á÷f/<`‚ƂɿEõX½z*ƒÏÒ?€ðJ\Î~‰Þ#ý¹t5À YT ?í!CkÂŽV‚‚2d¶›ú¦âÝwg²|ùDg†Dò³¦oæÉšë)®z~6Å9›Íªçòå4hšÉ‹±%PÑMÊ|D¹Ò½>@^žËû)li> ¡ýTmeøÔX.\¦YËX­"?þø£™9š»¥ñ)º8T¦L;ªTI.Ò,ÿ¿Y¬.)DI«¹£ô×C™«VMaРiúº0vìBfÏƾsÙœ<û#¯trý‚ht‰¿‰¿ßHO>QE AOóÒʇŽeèÐ9|øáXA5‡òeªñ—~ûwW;MÙf¹üv©‡®u¢nä6ªUJÃfSÈËSà¯*r-[6wÞ™ÁÖ{P.ðÁ¬ÝŽ#°o½x˜`±9Ÿ/9—Q‚ûn©ÚÕ3©_Ë•A4yØu^Q‹5í%0ЧžmÀO?ýdÚ®óf*V<… ¸®síZyîÝ;@™2¥ˆMõ9±°òý÷ßsæÜCˆºdL¶™ñ†@P‘§ÙY™(–Û~åtføè£I¼óÎ >üp,#GÎgÞ¼‘ȲBxd×®µgç÷{éúŒJw¥Â2LQB­=Š›q¡( qqc>|.qqc1bK–Œ#5)‘šßÑåÙTŽŸåʧpøÙÜ6Ø€$«, ©‘Š¢>¼¿-“ßנbéoøü«ÒL_ÈÌ9¯8íW}M¢Ug¿\ nµÀÝ$9¹"U*æQ¥bŸ,>Ïë#j±tÑWX,"ž~”ƒê[ÓT0Ÿ~x‘ ѹ,üÏN8‹¢(üöÛoEÈ;}è,ÍÌÜÀÀ¯ù´Œøª*æåýæ%ßBñB­*H»{F_{œÊªUª;¹lÙ Z å~R.!AjgÞJ­R€ÛãèQAð> 0wî(ÕV——»÷« H²¬˜Y’=?Ê”¸é<¢Ë–C–.ͨQóÕN2¦Þ£ Ëæ4 ]ÞÊÄI<Í<¤ Wzú1BCKW!?ÿ"wïöÃá¸H³fÍhÛ¢ð©=U*åRª)•ª˜ŒEcÎ"@é°tÀìÙ4kT†c'÷a·ÿMdä$ßäÈ‘X½ÑfÉÏÔßDæ°æœ=s*U#ð÷· (’$3~Ü0FØIóú!ÄM¹Bv¶È/W;¢þˆ‚9ßÀ½s³³sY¸ð}S§Øl"×Bˆ¨“ND¨DâßG)ÛŠÀ +—/¦"ŸÀ¿ë÷Žc#'5­uÊýÁñ;T"„?ÏfÓ¼•È0‰ŽmÙºé ÝzV&(Hä¿óç~Ò9¢œ)ƒ^½ÍoýèÞæ¿¬ŒH˜J«kólx¨zO¿=IÔ!û±÷t;º<ö-!þ9”Š”øtñ¦.ªÌôI›I¸yŸÁúè_t*º=II‡tVÐ&‰ iddl&)i$ÃÛo¿ÍäIwëpû-Øòã ÒKU­VÝ>ÐÂÐ ãŸ>òÍuG½!±6ê¾ýî{ßdüxuÿ¦°cÇ‡Š¶V¤, nµt$ œiúdf ?Ƶ„ R3ýÈÏ‘ˆŽÊ§É#™ÏÔŒ[»¶î)MRŠ êf¿ QQþtjüÆm?-E’Ø• óñŠ—i_û+Sý{É~4¨›Åºmh×!šÏý 3Àž}‘,\_k·¾u.SõË¥Fô)ýœ!“ª±ïHO=M㦮IQ¡÷x¾Ñ÷¦çýfóWU¤RÕG™4£Õ«W$&&ÆÍ<„Åb11§{ÐJÏNÑt|²*ÕÊ%P±t²W–:ùW0ç¯G‘-Er)¡ŒÎ5+Þ#ºd:µcîSÆ»xuáZ öÎæä_™8!3tho3¬I‹6ã³çMÇÆ=òÓ/á'Ý tx2¡y„ÉØ%i~ܸAj^-Þó‹—Œ+0ÓXÂëmW{Á]Ý’ROÒ¤Æ)*Fç’œbåÏ¿Ës_iG@P ²•ŽÓ²Î)$IàÄ™hnåµcƬÿ2wîA bD<±%S2$“¤?‹äÀõiÕ¾ÁÁVª•>CläQÅʾ#‘|±¯.OwŠeͪ¥ì^[@[!æŸÓ•d¸rß„;LXX ó¦> ¦Ô "C<3žÄ_à÷Ó%øü‡6T¯Yžm_šCÜ))GL‰*cÆ,båÊml˜ëOÛ¦V7©󯨲Ø9Èl˜@Û¦ëª\zôxÒ „=FñÙgs áeÉAS[6eûhÇeË& ( ï½÷–,ÏСê+ÀС ¹ö“J1®„q.­wìa¢ÀóX´h´¾¦j†œ¶1c1þ(ƒMR>¯˜ö5޽ùóGéëë¨Qó‰‹ã徊[Y6±˜úêÊFzÿýÎ,¦Šìß¿›Í¦QQQ¦=xð³)«jìØ8V®ÜFNNŽ)#9??Ÿ¼¼<òòòô”u»Ý®‰&$Y,¯J®àšÃ”Ò¦Ù­Zµ¢gϧ]Æb£Øºu)gO›\¤è™D®ÎX±â]Ö4U*†!Cf1sÆ(`¥ê¾Ø­¸D,O9U3t/ǰasœƒ$83£Ì®ga@2ù Šâ|E÷&Œƒ¯ý2üСsœJª¦…(NÀÈzàK³'´¶k©i~8–áÃçróæMÚ¶mËÏ?ÿl`ó¾Ãð𖤥ýìÑÒ÷ß_wkI¨ÆW÷=Æ­wÆÃ3¥ß³ž>‰¾ür±òâ‹Ãضm‘)> éð®\}ϽæÜ@…Aƒ¦³rå$ý³wÞ™ÁŠš’KïVpâLYnËÝ=–*±í>*ËŒÓï7l˜*O›Ÿ\WãŒV]e/ÍZ¶l¢+ÍSVt¯EÓ/\×L´X\ûàÁ³œb4'OžÔ9«Õêñ tF0¨?ZÞŠ*U¹z5Š7öb·;°ÛäçÛÉÏ·c·;L1õþ"‹hÐwDS¤W’dš6íE… GHHxœC‡Öë}n±ˆØlVUßܱ#Δîí"Ö銞Ÿ¨%«þ÷¿Sxë­i¬Z5EQx÷¹\Ù¯. ?üZ—œ€'Lþº1qÕÚ=4–ÑÄ-Ï gÐÆûN#ó¹Ú |ôÑ$¯Bë𦉉·¢(2hÐ4Õ+Y’ .˜h;88Ø+Ô<…g([âêÕh®^ý‡Ã¡ƒ@˱Ð&©+ÎàJšuBƒ=¨Xñ7=DžÐ‚cÇ>ÕëY­„;+F)×5,œ Œ3ì7&éÙÊL6cÖôaôn­z _ýþ<²_U¥AD=ã×óèjûÿ[Ñþå€ÕjÕ×tmã¬Ë…lAlì\[áÕl§k×Êÿs?‰F6Õ 1“VêÔéJ¥J§ Ûëe=8vòäç. Ê—_.vî0Â¥Ó{WÜ4@¼þúDÖ¯ŸIVz*‡¿û˜ÇŸìÆ‘kX³FÝã0uâBŽn•¹ÀtÉ=v®Î(єҮ•&³vítýõß*¸þÁØÇÏ0¼(‰¡îÏѯß|òÉLÿ„DýaW„ÐýàÔ`”ì´¿$*pùò7Ȳ–°«–cú€hØjÕ«w"&梳í²~mmÞ¸ñçÎíÔa‰ÒµëP¼ÁÛþ=oô¨uZ©Ü…Ô©ž‹,ÃOÔçÍ÷aõši$Çïã•§Oòõ‰'!¤žÇ/­­=˜ñßúôë÷6¸(üõ×'šÞûÃ÷æÖ¾öÚ6nœíñZ\_kûk¯MàÓOÿ£¸1e>77×dÜiÿÅÅ#+™¡"ññß’y“·ddUAˆíHL̼ïStçúõÄǃ°k×EQ kסÎßHòÜÈù0FP…Þ½Çqø³H*–ÍÓ¿¿x%Œ#¿Ùéù|.GÏ6D mkªc–GÍÔ¦!»OŸñzʹ±ôé3Nÿ¼89½{cÓ¦9…þm^þ|ƒ@Ÿ>j}mÖž­GQúYÚ/­¸@oñ 2‡õ˜ žyŠ®ë´iSË-uÝÁ•&"j•wî\B·nÃujv¢¾®¹ÿp£f ôî=ŽÍ›çñçÝ—ùáp©,äÛÂCs¨U#‚W†;#Ú›(ß8øFh¯‹HŸ>ãÙ¼yžþÞjµèÇ–-óéÓgV«E7Â|=z÷Ç–-ó¾·:Úu·nOïÞî×}ºnŸ>êu­V‹©ÏAÐ÷ZØl6Óà¹o³»r%Ü馋αA°Ð¦M=l6«~øùÙLïÕgPÿnÛ¶>‚`s†°­€ AÐ?ýo5ÎbEؽ{©bŒô¹– ×ZâbO¡FÓÜ}U÷|þ&³jÕ“û¥Ñ˜ÙêUñê«cÙºu¾ŽÚ‚f}£Ø¶m¡)`Š×ó{ô©ïƒ4¶Ð«ëé­ôì9Êp¾ÙµÔÜbQ [ý=ÐÔýg|\ÌàJ ™cÇκ¿¡Y³:Y Î}p2‚y}S™áŇ醛zNõÌuht·mÛ"ƒÛd6X\{aÍši 4Íô¹qÆYFÁDÑâÆfưXDÔZ£Lm+èèÑc;vÄ9ëº>W%ó¹Úu º¯ñèÙsÛ·ÇÎsõ‘¶vký`ü±R÷÷Î çXœû-­´hQßÄD*{©ŒÙ¬Y=ý\m¦ÊÆWãçVÁÂÿª»–k«IEND®B`‚SjaakII/misc/sjaakii.eng000644 000765 000024 00000000155 12433414314 016130 0ustar00eglebbkstaff000000 000000 plugin spec 0.0 sjaakii chess,shogi,xiangqi,shatranj,capablanca,dropchess,fairychess,shogivariants,asean SjaakII/cmake/FileList.cmake000644 000765 000024 00000000554 12452210627 016671 0ustar00eglebbkstaff000000 000000 set(SJAAK_SRC_FILES src/misc/aligned_malloc.c src/misc/cfgpath.c src/misc/genrand.c src/misc/keypressed.c src/misc/snprintf.c src/misc/softexp.c src/eval/pst.cc src/rules/game.cc src/rules/move.cc src/rules/san.cc src/rules/squares.cc src/hash/hashkey.c src/hash/hashtable.c src/hash/evalhash.c src/timer/timer.c ) SjaakII/cmake/FindReadline.cmake000644 000765 000024 00000000704 12433144250 017474 0ustar00eglebbkstaff000000 000000 # GNU Readline library finder if(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) set(READLINE_FIND_QUIETLY TRUE) endif(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h) FIND_LIBRARY(READLINE_LIBRARY NAMES readline) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG READLINE_LIBRARY READLINE_INCLUDE_DIR ) MARK_AS_ADVANCED(READLINE_INCLUDE_DIR READLINE_LIBRARY) SjaakII/include/aligned_malloc.h000644 000765 000024 00000000251 12433144250 017611 0ustar00eglebbkstaff000000 000000 #include #ifdef __cplusplus extern "C" { #endif void *aligned_malloc(size_t size, size_t align); void aligned_free(void *ptr); #ifdef __cplusplus } #endif SjaakII/include/assert.h000644 000765 000024 00000002142 12433144250 016161 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ASSERT_H #define ASSERT_H #include #include #ifdef DEBUGMODE #define assert(x) {if(!(x)){fprintf(stderr, "assert() failed in line %d of %s!\n", __LINE__, __FILE__); abort();}} #define trace(s) {fprintf(stderr, "%s in %s, line %d of %s.\n", s, __FUNCTION__, __LINE__, __FILE__);} #else #define assert(x) {} #define trace(x) {} #endif #endif SjaakII/include/betza_string.h000644 000765 000024 00000050347 12500060603 017357 0ustar00eglebbkstaff000000 000000 int slider_hopper_move_flags_to_betza(move_flag_t flags, char *buffer, size_t size) const { static struct { move_flag_t flags; const char *txt; } hopper_move_string[] = { { MF_SLIDER_H | MF_SLIDER_V | MF_SLIDER_D | MF_SLIDER_A, "Q" }, { MF_SLIDER_H | MF_SLIDER_V , "R" }, { MF_SLIDER_D | MF_SLIDER_A, "B" }, { MF_SLIDER_H , "sR" }, { MF_SLIDER_V , "vR" }, { MF_SLIDER_D , "rflbB" }, { MF_SLIDER_A, "lfrbB" }, { 0, NULL } }; int n = 0; const char *hop = ""; while (is_slider(flags) || is_hopper(flags)) { if (is_slider(flags)) { for (int k=0; hopper_move_string[k].flags; k++) { if ((flags & hopper_move_string[k].flags) == hopper_move_string[k].flags) { n += snprintf(buffer+n, size-n, "%s%s", hop, hopper_move_string[k].txt); flags &= ~hopper_move_string[k].flags; } } flags &= ~MF_SLIDER; } if (is_hopper(flags)) { flags |= (flags >> 4) & MF_SLIDER; hop = "p"; flags &= ~MF_HOPPER; } } return n; } int leaper_move_flags_to_betza(move_flag_t flags, char *buffer, size_t size) const { int n = 0; enum sym4_t { V, S, F, B, L, R, RF4, LF4, RB4, LB4, NUM_SYM4 }; enum sym8_t { FL, LF, FR, RF, BL, LB, BR, RB, FF, BB, LL, RR, FH, BH, LH, RH, NUM_SYM8 }; static const char *leaper_move_string[] = { "*WDH", "WFNC", "DNAZ", "HCZG" }; static struct { int dx, dy; const char *txt; int symmetry; } leaper_description[] = { { 1, 0, "W", 4 }, { 1, 1, "F", 4 }, { 2, 0, "D", 4 }, { 2, 1, "N", 8 }, { 2, 2, "A", 4 }, { 3, 0, "H", 4 }, { 3, 1, "C", 8 }, { 3, 2, "Z", 8 }, { 3, 3, "G", 4 }, { 0, 0, NULL, 0 } }; bitboard_t sym4[NUM_SYM4]; const char *sym4txt[NUM_SYM4]; bitboard_t sym8[NUM_SYM8]; const char *sym8txt[NUM_SYM8]; sym4txt[V] = "v"; sym4txt[S] = "s"; sym4txt[F] = "f"; sym4txt[B] = "b"; sym4txt[L] = "l"; sym4txt[R] = "r"; sym4txt[RF4] = "rf"; sym4txt[LF4] = "lf"; sym4txt[RB4] = "rb"; sym4txt[LB4] = "lb"; sym8txt[FH] = "fh"; sym8txt[BH] = "bh"; sym8txt[LH] = "lh"; sym8txt[RH] = "rh"; sym8txt[FF] = "ff"; sym8txt[BB] = "bb"; sym8txt[LL] = "ll"; sym8txt[RR] = "rr"; sym8txt[FL] = "fl"; sym8txt[LF] = "lf"; sym8txt[FR] = "fr"; sym8txt[RF] = "rf"; sym8txt[BL] = "bl"; sym8txt[LB] = "lb"; sym8txt[BR] = "br"; sym8txt[RB] = "rb"; /* Lame leapers */ const char *block = ""; if (is_masked_leaper(flags)) { move_flag_t f = flags & MF_LEAPER_MASK; flags &= ~MF_LEAPER_FLAGS; flags |= (f >> 8) | MF_IS_LEAPER; block = "n"; } /* Simple leapers */ if (is_simple_leaper(flags)) { int index = get_leaper_index(flags); /* Some combination of simple leapers, this is a bit complicated. * We use the following algorithm: * - Find the square where the leaper has maximum mobility. * - Find the simple leaper that has the largest overlap (test the King first) * - If the overlap is complete, we are done. If not, we need to extract directions. * - Repeat until all compound leapers have been identified. */ /* Find the square where the leaper has best mobility. * We need this because the movement tables could have been hacked to exclude certain regions of the board. */ bitboard_t leaper; int square = 0; int max_moves = 0; for (int nn=0; nn bb = is_aleaper(flags) ? movegen.aleaper[WHITE][index][nn] : movegen.leaper[index][nn]; int moves = bb.popcount(); if (moves > max_moves || (moves == max_moves && nn < 4*files)) { /* Don't get stuck on back rank */ max_moves = moves; square = nn; leaper = bb; } } /* Construct symmetry masks */ if (is_aleaper(flags)) { bitboard_t fd, bd, fa, ba; int rank = unpack_rank(square); int file = unpack_file(square); int diag = bitboard_t::diagonal_nr[square]; int anti = bitboard_t::anti_diagonal_nr[square]; sym4[F] = bitboard_t::board_northward[rank]; sym4[B] = bitboard_t::board_southward[rank]; sym4[R] = bitboard_t::board_eastward[file]; sym4[L] = bitboard_t::board_westward[file]; sym4[V] = sym4[F] | sym4[B]; sym4[S] = sym4[R] | sym4[L]; sym4[RF4] = sym4[R] & sym4[L]; sym4[LF4] = sym4[L] & sym4[L]; sym4[RB4] = sym4[R] & sym4[B]; sym4[LB4] = sym4[L] & sym4[B]; sym8[FH] = sym4[F]; sym8[BH] = sym4[B]; sym8[LH] = sym4[L]; sym8[RH] = sym4[R]; fd.clear(); for (int n = diag+1; n<16; n++) fd |= bitboard_t::board_diagonal[n]; fa.clear(); for (int n = anti+1; n<16; n++) fa |= bitboard_t::board_antidiagonal[n]; bd.clear(); for (int n = 0; n < diag; n++) bd |= bitboard_t::board_diagonal[n]; ba.clear(); for (int n = 0; n < anti; n++) ba |= bitboard_t::board_antidiagonal[n]; sym8[FF] = fd & fa; sym8[BB] = bd & ba; sym8[LL] = fd & ba; sym8[RR] = bd & fa; sym8[FL] = sym8[FH] & sym8[LL]; sym8[LF] = sym8[LH] & sym8[FF]; sym8[FR] = sym8[FH] & sym8[RR]; sym8[RF] = sym8[RH] & sym8[FF]; sym8[BL] = sym8[BH] & sym8[LL]; sym8[LB] = sym8[LH] & sym8[BB]; sym8[BR] = sym8[BH] & sym8[RR]; sym8[RB] = sym8[RH] & sym8[BB]; } /* Find which combination of simple leapers matches best. * We try the non-atom king first. */ bitboard_t kb = movegen.make_leaper_bitboard(square, 1, 1)|movegen.make_leaper_bitboard(square, 1, 0); if (leaper == kb) { n += snprintf(buffer+n, size-n, "K"); leaper.clear(); } /* Loop over all fundamental leapers. * FIXME: the loop can become infinite if the leaper is long (> 4) in any direction. */ while (!leaper.is_empty()) { bitboard_t best_leaper; int best = -1; int best_count = 0; for (int nn = 0; leaper_description[nn].txt; nn++) { int dx = leaper_description[nn].dx; int dy = leaper_description[nn].dy; bitboard_t bb = movegen.make_leaper_bitboard(square, dx, dy); int count = (bb & leaper).popcount(); if (count > best_count) { best_count = count; best = nn; best_leaper = bb; if (leaper == bb) break; } } if (best == -1) break; /* Break out if nothing matches */ if ((leaper & best_leaper) == best_leaper) { n += snprintf(buffer+n, size-n, "%s%s", block, leaper_description[best].txt); } else { assert(is_aleaper(flags)); /* Only some of the directions match, find out which */ if (leaper_description[best].symmetry == 4) { /* 4-point symmetry */ while (!(leaper & best_leaper).is_empty()) { int best = -1; int best_count = 0; for (int k = 0; k bb = sym4[k] & best_leaper & leaper; int count = bb.popcount(); if (count > best_count) { best_count = count; best = k; } } if (best == -1) break; /* Break out if nothing matches */ n += snprintf(buffer+n, size-n, "%s", sym4txt[best]); leaper &= ~(best_leaper & sym4[best]); } } else if (leaper_description[best].symmetry == 8) { /* 8-point symmetry */ while (!(leaper & best_leaper).is_empty()) { int best = -1; int best_count = 0; for (int k = 0; k bb = sym8[k] & best_leaper & leaper; int count = bb.popcount(); if (count > best_count) { best_count = count; best = k; } } if (best == -1) break; /* Break out if nothing matches */ n += snprintf(buffer+n, size-n, "%s", sym8txt[best]); leaper &= ~(best_leaper & sym8[best]); } } n += snprintf(buffer+n, size-n, "%s%s", block, leaper_description[best].txt); } leaper &= ~best_leaper; } } return n; } int stepper_move_flags_to_betza(move_flag_t flags, char *buffer, size_t size) const { if (!is_stepper(flags)) return 0; int n = 0; enum sym4_t { A, V, S, F, B, L, R, RF4, LF4, RB4, LB4, NUM_SYM4 }; bitboard_t sym4[NUM_SYM4]; const char *sym4txt[NUM_SYM4]; sym4txt[A] = ""; sym4txt[V] = "v"; sym4txt[S] = "s"; sym4txt[F] = "f"; sym4txt[B] = "b"; sym4txt[L] = "l"; sym4txt[R] = "r"; sym4txt[RF4] = "rf"; sym4txt[LF4] = "lf"; sym4txt[RB4] = "rb"; sym4txt[LB4] = "lb"; int square = bitboard_t::pack_rank_file(ranks/2, files/2); int rank = unpack_rank(square); int file = unpack_file(square); sym4[A] = bitboard_t::board_all; sym4[F] = bitboard_t::board_northward[rank]; sym4[B] = bitboard_t::board_southward[rank]; sym4[R] = bitboard_t::board_eastward[file]; sym4[L] = bitboard_t::board_westward[file]; sym4[V] = sym4[F] | sym4[B]; sym4[S] = sym4[R] | sym4[L]; sym4[RF4] = sym4[R] & sym4[F]; sym4[LF4] = sym4[L] & sym4[F]; sym4[RB4] = sym4[R] & sym4[B]; sym4[LB4] = sym4[L] & sym4[B]; bitboard_t atombb[2]; atombb[0] = movegen.make_leaper_bitboard(square, 1, 0); atombb[1] = movegen.make_leaper_bitboard(square, 1, 1); int si = get_stepper_index(flags); int dim = std::max(files, ranks)-1; /* Decompose the stepper. * The array index runs over the number of steps, bit indicate which directions are possible. */ #if defined _MSC_VER std::vector direction_mask(dim, 0); #else uint8_t direction_mask[dim]; memset(direction_mask, 0, dim); #endif /* Check for single stepper moves, which are generated in parallel */ for (int d=0; d<8; d++) { int max_c = (movegen.stepper_description[si][WHITE] >> (d*4)) & 15; if (max_c > dim) max_c = dim; for (int c = 0; c= 0; c--) { if (direction_mask[c] == 0) continue; /* Atoms that describe the motion, decompose in F and W */ const char *atom[2] = { "W", "F" }; char countstr[10]; countstr[0] = 0; if (c == dim-1) { atom[0] = "R"; atom[1] = "B"; } else if (c > 0) { snprintf(countstr, 10, "%d", c+1); } /* Construct move atom */ bitboard_t moves; for (int d=0; d<8; d++) { if ((direction_mask[c] & (1< bb = sym4[kk] & atombb[ai] & moves; int count = bb.popcount(); if (count > best_count) { best_count = count; best = kk; } } if (best == -1) break; /* Break out if nothing matches */ /* Make sure directions are unambiguous for diagonal atoms by repeating the last direction if needed. * Due to the way the matching works, the first iteration will always try to match the SVFBRL directions. * This maps (NW,NE,SE) -> fF + SE -> ffrbF. */ if (ai == 2 && strlen(sym4txt[best]) == 2 && k == 1) k += snprintf(s+k, sizeof(s)-k, "%c", s[k-1]); k += snprintf(s+k, sizeof(s)-k, "%s", sym4txt[best]); moves &= ~(sym4[k]&atombb[ai]); } n += snprintf(buffer+n, size-n, "%s%s%s", s, atom[ai], countstr); } /* Mask these directions for all lower-number directions */ for (int k = c-1; k>=0; k--) direction_mask[k] &= ~direction_mask[c]; } return n; } const char *move_flags_to_betza(move_flag_t flags, char *buffer = NULL, size_t size = 256) const { static char static_buffer[256] = { 0 }; int n = 0; if (buffer == NULL) { buffer = static_buffer; size = sizeof static_buffer; } buffer[0] = 0; if (flags == 0) goto done; buffer[0] = '?'; buffer[1] = 0; /* Describe slider moves */ n += slider_hopper_move_flags_to_betza(flags, buffer + n, size - n); flags &= ~MF_SLIDER; flags &= ~MF_HOPPER; if (flags == 0) goto done; /* Describe leaper moves */ n += leaper_move_flags_to_betza(flags, buffer + n, size - n); flags &= ~MF_LEAPER_FLAGS; if (flags == 0) goto done; /* Describe stepper moves */ n += stepper_move_flags_to_betza(flags, buffer + n, size - n); flags &= ~MF_STEPPER; if (flags == 0) goto done; done: return buffer; } const char *piece_moves_to_betza(int piece, char *buffer = NULL, size_t size = 256) const { const char *post_movetype = "pn"; char s_string[256] = { 0 }; char m_string[256] = { 0 }; char c_string[256] = { 0 }; char i_string[256] = { 0 }; static char static_buffer[768] = { 0 }; char *s; int n = 0; if (buffer == NULL) { buffer = static_buffer; size = sizeof static_buffer; } buffer[0] = 0; move_flag_t move = pt.piece_move_flags[piece]; move_flag_t capture = pt.piece_capture_flags[piece]; move_flag_t initial = pt.piece_special_move_flags[piece]; move_flags_to_betza(move, m_string, sizeof(m_string)); move_flags_to_betza(capture, c_string, sizeof(c_string)); move_flags_to_betza(initial, i_string, sizeof(i_string)); /* Eliminate duplicates between the normal move and the initial move */ if ((s = strstr(i_string, m_string))) { size_t n1 = strlen(m_string); size_t n2 = strlen(i_string); char *p = s + n1; if (!isdigit(p[0])) for (size_t k = 0; k <= (n2-n1); k++) { s[k] = p[k]; s[k+1] = 0; if (s[k] == 0) break; } } if (move == capture) { strncpy(s_string, m_string, sizeof s_string); m_string[0] = c_string[0] = 0; } /* Move options common to move and capture to a shared string */ if (c_string[0] && (s = strstr(c_string, m_string))) { if (s == c_string || isupper(s[-1])) { strncpy(s_string, m_string, sizeof s_string); m_string[0] = 0; size_t n1 = strlen(s_string); size_t n2 = strlen(c_string); char *p = s + n1; if (!isdigit(p[0])) for (size_t k = 0; k <= (n2-n1); k++) { s[k] = p[k]; s[k+1] = 0; if (s[k] == 0) break; } } } if (m_string[0] && (s = strstr(m_string, c_string))) { if (s == m_string || isupper(s[-1])) { strncpy(s_string, c_string, sizeof s_string); c_string[0] = 0; size_t n1 = strlen(s_string); size_t n2 = strlen(m_string); char *p = s + n1; if (!isdigit(p[0])) for (size_t k = 0; k <= (n2-n1); k++) { s[k] = p[k]; s[k+1] = 0; if (s[k] == 0) break; } } } /* Common between move and capture */ n += snprintf(buffer+n, size-n, "%s", s_string); /* Pure moves */ size_t l = strlen(m_string); for (size_t k=0; k side = bitboard_t::board_east_edge | bitboard_t::board_west_edge; bitboard_t bb = movegen.castle_mask[SHORT][WHITE] & movegen.castle_mask[LONG][WHITE]; int s1 = bb.bitscan(); int s2 = movegen.castle_king_dest[SHORT][WHITE]; n += snprintf(buffer+n, size-n, "%ss", (initial) ? "" : "i"); bb = movegen.castle_mask[SHORT][WHITE]; bb.reset(s1); int s3 = bb.bitscan(); if ((side & bb).is_empty() && bitboard_t::board_all.test(s3+1)) n += snprintf(buffer+n, size-n, "j"); n += snprintf(buffer+n, size-n, "O%d", abs(s2-s1)); } if (strlen(buffer) == 0) { /* Hack: try to convince XBoard that this piece can do anything */ snprintf(buffer, size, "QNCZt"); } /* Drop extension, * http://www.talkchess.com/forum/viewtopic.php?p=612101#612101 */ if (board.rule_flags & RF_USE_DROPS) { bool print = false; /* No drops on first file */ if ((pt.drop_zone[WHITE][piece] & bitboard_t::board_rank[0]).is_empty()) { n += snprintf(buffer+n, size-n, "j"); print = true; } /* Restriction on number of pieces of this type, board */ if (pt.piece_maximum[piece][WHITE]<128 && !(pt.piece_maximum[piece][WHITE]==1 && (pt.piece_flags[piece]&PF_ROYAL))) { print = true; for (int k = 0; k 0 && (pt.drop_zone[WHITE][piece] & bitboard_t::board_rank[last_rank-1]).is_empty()) last_rank--; if (last_rank != ranks) print = true; if (print) { n += snprintf(buffer+n, size-n, "@"); if (last_rank != ranks) n += snprintf(buffer+n, size-n, "%d", last_rank); } } return buffer; } SjaakII/include/bitboard.h000644 000765 000024 00000045141 12470157255 016466 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BITBOARD_H #define BITBOARD_H #include #include #include "assert.h" #include "bits.h" #include "squares.h" template class bitboard_t { public: kind bb; public: static int board_files, board_ranks; static uint32_t rank_mask; static uint32_t file_mask; static uint8_t diagonal_nr[sizeof(kind)*8]; static uint8_t anti_diagonal_nr[sizeof(kind)*8]; static bitboard_t king_zone[2][sizeof(kind)*8]; static bitboard_t neighbour_board[sizeof(kind)*8]; static bitboard_t square_bitboards[sizeof(kind)*8]; static bitboard_t board_empty; static bitboard_t board_all; static bitboard_t board_edge; static bitboard_t board_corner; static bitboard_t board_east_edge; static bitboard_t board_west_edge; static bitboard_t board_north_edge; static bitboard_t board_south_edge; static bitboard_t board_light; static bitboard_t board_dark; static bitboard_t board_centre; static bitboard_t board_xcentre; static bitboard_t board_xxcentre; static bitboard_t board_rank[16]; static bitboard_t board_file[16]; static bitboard_t board_file_mask; static bitboard_t board_south; static bitboard_t board_north; static bitboard_t board_northward[16]; static bitboard_t board_southward[16]; static bitboard_t board_eastward[16]; static bitboard_t board_westward[16]; static bitboard_t board_homeland[2]; static bitboard_t board_diagonal[32]; static bitboard_t board_antidiagonal[32]; static bitboard_t board_between[sizeof(kind)*8][sizeof(kind)*8]; static void initialise_bitboards(int files, int ranks); bitboard_t() : bb(0) { } bitboard_t(const kind &b) : bb(b) { } kind value() { return bb; } bitboard_t operator = (const bitboard_t& b) { bb = b.bb; return *this; } /* Default function definitions, should work with any normal integer * type, but can be overridden if a more optimal solution is * possible. */ void clear() { bb ^= bb; }; bool onebit() const { return (bb & (bb-1)) == 0; } bool twobit() const { if (onebit()) return false; kind b = bb & (bb-1); return (b & (b-1)) == 0; } int popcount() const { kind x = bb; int count = 0; while (x) { count++; x &= x-1; } return count; } int bitscan() const { kind x = bb; int i = 0; while (x && !(x&1)) { i++; x>>=1; } return i; } int msb() const { kind x = bb; int n = 8*sizeof(kind)-1; assert(x); while ((x&((kind)1< sshift(int bits) const { if (bits>0) return bitboard_t(bb << bits); return bitboard_t(bb >> (-bits)); } inline bool is_empty() const { return bb == 0; } /* Default definitions of operators */ inline bool operator == (const bitboard_t& b2) const { return bb == b2.bb; } inline bool operator != (const bitboard_t& b2) const { return !(*this == b2); } inline bitboard_t operator << (const int bits) const { return bitboard_t(bb << bits); } inline bitboard_t operator >> (const int bits) const { return bitboard_t(bb >> bits); } inline bitboard_t operator ~() const { return bitboard_t(~bb); } inline bitboard_t operator |(const bitboard_t &b2) const { return bitboard_t(bb | b2.bb); } inline bitboard_t operator &(const bitboard_t &b2) const { return bitboard_t(bb & b2.bb); } inline bitboard_t operator ^(const bitboard_t &b2) const { return bitboard_t(bb ^ b2.bb); } inline bitboard_t& operator |=(const bitboard_t &b2) { bb |= b2.bb; return *this; } inline bitboard_t& operator &=(const bitboard_t &b2) { bb &= b2.bb; return *this; } inline bitboard_t& operator ^=(const bitboard_t &b2) { bb ^= b2.bb; return *this; } inline uint32_t get_rank(int rank) const { assert(rank < board_ranks); bitboard_t b = (*this) >> (rank * board_files); return (uint32_t)(b.bb & rank_mask); } inline uint32_t get_file(int file) const { #if 0 uint32_t file_bits = 0; int n; int bit = file; for (n=0; n b(bb); b = (b >> file) & board_file_mask; do { b |= (b >> (shift * board_files)) << shift; shift <<= 1; //b |= (b >> board_files) << 1; //shift++; } while (shift < board_ranks); return (uint32_t)(b.bb & file_mask); #endif } bitboard_t fill_north() const { int shift = 1; bitboard_t b(bb); do { b |= (b << (shift * board_files)); shift <<= 1; } while (shift < board_ranks); return b; } inline bitboard_t fill_south() const { int shift = 1; bitboard_t b(bb); do { b |= (b >> (shift * board_files)); shift <<= 1; } while (shift < board_ranks); return b; } char *rank_string(int rank, char *buffer = NULL) const { static char static_buffer[256]; if (buffer == NULL) buffer = static_buffer; char *s = buffer; uint32_t bits = get_rank(rank); for (int bit = 0; bit < board_files; bit++) { if (bits & (1 << bit)) *s = '1'; else *s = '.'; s++; } *s = '\0'; return buffer; } void print(const char *msg = NULL) const { for (int n = 0; n int bitboard_t::board_files; template int bitboard_t::board_ranks; template uint32_t bitboard_t::rank_mask; template uint32_t bitboard_t::file_mask; template uint8_t bitboard_t::diagonal_nr[sizeof(kind)*8]; template uint8_t bitboard_t::anti_diagonal_nr[sizeof(kind)*8]; template bitboard_t bitboard_t::king_zone[2][sizeof(kind)*8]; template bitboard_t bitboard_t::neighbour_board[sizeof(kind)*8]; template bitboard_t bitboard_t::square_bitboards[sizeof(kind)*8]; template bitboard_t bitboard_t::board_empty; template bitboard_t bitboard_t::board_all; template bitboard_t bitboard_t::board_edge; template bitboard_t bitboard_t::board_corner; template bitboard_t bitboard_t::board_east_edge; template bitboard_t bitboard_t::board_west_edge; template bitboard_t bitboard_t::board_north_edge; template bitboard_t bitboard_t::board_south_edge; template bitboard_t bitboard_t::board_light; template bitboard_t bitboard_t::board_dark; template bitboard_t bitboard_t::board_centre; template bitboard_t bitboard_t::board_xcentre; template bitboard_t bitboard_t::board_xxcentre; template bitboard_t bitboard_t::board_rank[16]; template bitboard_t bitboard_t::board_file[16]; template bitboard_t bitboard_t::board_file_mask; template bitboard_t bitboard_t::board_south; template bitboard_t bitboard_t::board_north; template bitboard_t bitboard_t::board_northward[16]; template bitboard_t bitboard_t::board_southward[16]; template bitboard_t bitboard_t::board_eastward[16]; template bitboard_t bitboard_t::board_westward[16]; template bitboard_t bitboard_t::board_homeland[2]; template bitboard_t bitboard_t::board_diagonal[32]; template bitboard_t bitboard_t::board_antidiagonal[32]; template bitboard_t bitboard_t::board_between[sizeof(kind)*8][sizeof(kind)*8]; template inline void bitboard_t::initialise_bitboards(int files, int ranks) { board_ranks = ranks; board_files = files; assert(ranks * files <= 8*sizeof(kind)); rank_mask = (1< size) board_north_edge |= square_bitboards[n]; } board_edge = board_south_edge | board_north_edge | board_east_edge | board_west_edge; board_corner = (board_south_edge | board_north_edge) & (board_east_edge | board_west_edge); for (n=0; n> files); neighbour_board[n] |= (neighbour_board[n] & ~board_west_edge) >> 1; neighbour_board[n] |= (neighbour_board[n] & ~board_east_edge) << 1; king_zone[0][n] = king_zone[1][n] = neighbour_board[n]; king_zone[0][n] |= neighbour_board[n] << files; king_zone[1][n] |= neighbour_board[n] >> files; neighbour_board[n] &= ~square_bitboards[n]; king_zone[0][n] &= ~square_bitboards[n]; king_zone[1][n] &= ~square_bitboards[n]; } /* Set up diagonals and anti-diagonals * For the mapping of diagonal numbers, we pretend the board is square; it may not be, but this is easiest. */ int s = files; if (ranks > files) s = ranks; for (n = 0; n<32; n++) { diagonal_nr[n] = 255; anti_diagonal_nr[n] = 255; } for (n = 0; n::board_south = bitboard_t::board_north = bitboard_t::board_empty; for (n=0; n centre_files, centre_ranks; for (int f = files/2 - 1; f::anti_diagonal_nr[square] == anti_diagonal_nr[attack]) { for (int n=square;n<=(attack);n+=board_files-1) board_between[square][attack] |= square_bitboards[n]; } board_between[square][attack].reset(square); board_between[square][attack].reset(attack); board_between[attack][square] = board_between[square][attack]; } } board_file_mask = board_file[0]; } /* Specialisation for 32 bits: use optimised functions */ template<> inline int bitboard_t::popcount() const { return popcount32(bb); } template<> inline int bitboard_t::bitscan() const { return bitscan32(bb); } template<> inline int bitboard_t::lsb() const { return lsb32(bb); } template<> inline int bitboard_t::msb() const { return msb32(bb); } /* Specialisation for 64 bits: use optimised functions */ template<> inline int bitboard_t::popcount() const { return popcount64(bb); } template<> inline int bitboard_t::bitscan() const { return bitscan64(bb); } template<> inline int bitboard_t::lsb() const { return lsb64(bb); } template<> inline int bitboard_t::msb() const { return msb64(bb); } template<> inline int bitboard_t::popcount() const { return popcount128(bb); } template<> inline int bitboard_t::bitscan() const { return bitscan128(bb); } template<> inline int bitboard_t::lsb() const { return lsb128(bb); } template<> inline int bitboard_t::msb() const { return msb128(bb); } template<> inline bool bitboard_t::onebit() const { return onebit128(bb); } template<> inline bitboard_t bitboard_t::operator << (const int bits) const { return bitboard_t(shl128(bb, bits)); } template<> inline bitboard_t bitboard_t::operator >> (const int bits) const { return bitboard_t(shr128(bb, bits)); } template<> inline bool bitboard_t::test(int bit) const { return test128(bb, bit); } template<> inline bool bitboard_t::is_empty() const { return is_zero128(bb); } #ifndef HAVE_UINT128_T template<> inline uint32_t bitboard_t::get_rank(int rank) const { uint128_t b; b = shr128(bb, rank * board_files); return b.i64[0] & rank_mask; } template<> inline uint32_t bitboard_t::get_file(int file) const { uint32_t file_bits = 0; int n; int bit = file; for (n=0; n. */ #include "bits32.h" #include "bits64.h" #include "bits128.h" SjaakII/include/bits128.h000644 000765 000024 00000024462 12452210627 016070 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BITS128_H #define BITS128_H #include #include "bits64.h" #if defined __x86_64__ #define HAVE_UINT128_T 1 #endif #if HAVE_UINT128_T typedef __uint128_t uint128_t; static inline uint128_t u128(uint64_t u1, uint64_t u2) { return (uint128_t)u2 << 64 | u1; } static inline bool onebit128(uint128_t x) { return (x & (x-1)) == 0; } static inline int bitscan128(uint128_t x) { if (x & (uint128_t)0xFFFFFFFFFFFFFFFFll<<64) return 64 + bitscan64(x>>64); else return bitscan64(x); } static inline int lsb128(uint128_t x) { if ((x & (uint128_t)0xFFFFFFFFFFFFFFFFll) == 0) return 64 + lsb64(x>>64); else return lsb64(x); } static inline int msb128(uint128_t x) { if (x & (uint128_t)0xFFFFFFFFFFFFFFFFll<<64) return 64 + msb64(x>>64); else return msb64(x); } static inline int popcount128(uint128_t x) { return popcount64(x >> 64) + popcount64(x); } static inline uint128_t shr128(uint128_t x, int bits) { return x >> bits; } static inline uint128_t shl128(uint128_t x, int bits) { return x << bits; } static inline uint128_t mul128(uint128_t x, uint128_t y) { return x * y; } static inline uint128_t sshift128(uint128_t x, int s) { if (s>0) return shl128(x, s); return shr128(x, -s); #if 0 signed char left = (signed char) s; signed char right = -((signed char)(s >> 8) & left); return shl128(shr128(x, right), right + left); #endif } static inline bool test128(uint128_t x, int bit) { return shr128(x, bit) & 0x01; } static inline bool is_zero128(uint128_t x) { return x == 0; } static inline bool is_equal128(uint128_t x, uint128_t y) { return x == y; } #else #ifdef __cplusplus struct uint128_t { uint64_t i64[2]; uint128_t() { i64[0] = 0; i64[1] = 0; } uint128_t(int i) { i64[0] = i; i64[1] = 0; } uint128_t(uint64_t u1, uint64_t u2) { i64[0] = u1; i64[1] = u2; } inline uint128_t operator << (const int bits) const { uint64_t u1 = i64[0]; uint64_t u2 = i64[1]; if (bits >= 64) { u2 = u1 << (bits-64); u1 = 0; } else if (bits > 0) { uint64_t uu = u1 >> (64 - bits); u2 <<= bits; u1 <<= bits; u2 |= uu; } return uint128_t(u1, u2); } inline uint128_t operator >> (const int bits) const { uint64_t u1 = i64[0]; uint64_t u2 = i64[1]; if (bits >= 64) { u1 = u2 >> (bits-64); u2 = 0; } else if (bits > 0) { uint64_t uu = u2 << (64 - bits); u1 >>= bits; u2 >>= bits; u1 |= uu; } return uint128_t(u1, u2); } inline bool operator == (const uint128_t y) const { return (i64[0] == y.i64[0]) && (i64[1] == y.i64[1]); } inline bool operator != (const uint128_t y) const { return !(*this == y); } inline uint128_t operator |=(const uint128_t &x) { i64[0] |= x.i64[0]; i64[1] |= x.i64[1]; return *this; } inline uint128_t operator &=(const uint128_t &x) { i64[0] &= x.i64[0]; i64[1] &= x.i64[1]; return *this; } inline uint128_t operator ^=(const uint128_t &x) { i64[0] ^= x.i64[0]; i64[1] ^= x.i64[1]; return *this; } inline uint128_t operator +=(const uint128_t &x) { i64[0] += x.i64[0]; i64[1] += x.i64[1]; return *this; } inline uint128_t operator -=(const uint128_t &x) { i64[0] -= x.i64[0]; i64[1] -= x.i64[1]; return *this; } inline uint128_t operator ~ () const { return uint128_t(~i64[0], ~i64[1]); } inline uint128_t operator | (const uint128_t &x) const { return uint128_t(*this) |= x; } inline uint128_t operator & (const uint128_t &x) const { return uint128_t(*this) &= x; } inline uint128_t operator ^ (const uint128_t &x) const { return uint128_t(*this) ^= x; } inline uint128_t operator + (const uint128_t &x) const { return uint128_t(*this) += x; } inline uint128_t operator - (const uint128_t &x) const { return uint128_t(*this) -= x; } }; inline uint128_t operator - (int lhs, const uint128_t &x) { return uint128_t(lhs) -= x; } inline uint128_t operator + (int lhs, const uint128_t &x) { return uint128_t(lhs) += x; } static inline uint128_t u128(uint64_t u1, uint64_t u2) { return uint128_t(u1, u2); } static inline bool onebit128(uint128_t x) { uint64_t u1 = x.i64[0]; uint64_t u2 = x.i64[1]; return onebit64(u1 ^ u2) && onebit64(u1 | u2); } static inline int bitscan128(uint128_t x) { if (x.i64[1]) return 64 + bitscan64(x.i64[1]); else return bitscan64(x.i64[0]); } static inline int lsb128(uint128_t x) { if (x.i64[0] == 0) return 64 + lsb64(x.i64[1]); else return lsb64(x.i64[0]); } static inline int msb128(uint128_t x) { if (x.i64[1]) return 64 + msb64(x.i64[1]); else return msb64(x.i64[0]); } static inline int popcount128(uint128_t x) { return popcount64(x.i64[0]) + popcount64(x.i64[1]); } static inline uint128_t shr128(uint128_t x, int bits) { return x >> bits; } static inline uint128_t shl128(uint128_t x, int bits) { return x << bits; } static inline bool test128(uint128_t x, int bit) { if (bit < 64) return (x.i64[0] >> bit) & 0x01; return (x.i64[1] >> (bit-64)) & 0x01; } static inline bool is_zero128(uint128_t x) { uint64_t x1 = x.i64[0]; uint64_t x2 = x.i64[1]; return (x1 | x2) == 0; } static inline bool is_equal128(uint128_t x, uint128_t y) { return x == y; } #else typedef uint64_t uint128_t __attribute__ ((vector_size(sizeof(uint64_t)*2), aligned(8))); static inline uint128_t u128(uint64_t u1, uint64_t u2) { return (uint128_t){u1, u2}; } static inline bool onebit128(uint128_t x) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; uint64_t u1 = xx.i64[0]; uint64_t u2 = xx.i64[1]; return onebit64(u1 ^ u2) && onebit64(u1 | u2); } static inline int bitscan128(uint128_t x) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; if (xx.i64[1]) return 64 + bitscan64(xx.i64[1]); else return bitscan64(xx.i64[0]); } static inline int lsb128(uint128_t x) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; if (xx.i64[0] == 0) return 64 + lsb64(xx.i64[1]); else return lsb64(xx.i64[0]); } static inline int msb128(uint128_t x) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; if (xx.i64[1]) return 64 + msb64(xx.i64[1]); else return msb64(xx.i64[0]); } static inline int popcount128(uint128_t x) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; return popcount64(xx.i64[0]) + popcount64(xx.i64[1]); } static inline uint128_t shr128(uint128_t x, int bits) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t y; y.i128 = x; uint64_t u1 = y.i64[0]; uint64_t u2 = y.i64[1]; if (bits >= 64) { u1 = u2 >> (bits-64); u2 = 0; } else if (bits > 0) { uint64_t uu = u2 << (64 - bits); u1 >>= bits; u2 >>= bits; u1 |= uu; } return (uint128_t){u1, u2}; } static inline uint128_t shl128(uint128_t x, int bits) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; uint64_t u1 = xx.i64[0]; uint64_t u2 = xx.i64[1]; if (bits >= 64) { u2 = u1 << (bits-64); u1 = 0; } else if (bits > 0) { uint64_t uu = u1 >> (64 - bits); u2 <<= bits; u1 <<= bits; u2 |= uu; } return (uint128_t){u1, u2}; } static inline uint128_t mul128(uint128_t x, uint128_t y) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx, yy; xx.i128 = x; yy.i128 = y; uint64_t x1 = xx.i64[0]; uint64_t x2 = xx.i64[1]; uint64_t y1 = yy.i64[0]; uint64_t y2 = yy.i64[1]; uuint128_t r, q, w; /* Multiply upper word */ w.i128 = u128(0, y1*x2 + x1*y2); /* Lower word, but we have to be careful about carries */ q.i128 = u128(y1,0); r.i128 = u128(0,0); while (x1 > 0) { if (x1 & 0x1) { uint64_t r1 = r.i64[0]; r.i128 += q.i128; /* Carry */ r.i64[1] += (r.i64[0] < r1 || r.i64[0] < q.i64[0]); } int n = 1; x1 >>= 1; while (x1 && !(x1 & 0x1)) {x1>>=1; n++;} q.i128 = shl128(q.i128, n); } q.i128 = r.i128 + w.i128; if (q.i64[0] < r.i64[0] || q.i64[0] < w.i64[0]) q.i64[1]++; return q.i128; } static inline uint128_t sshift128(uint128_t x, int s) { if (s>0) return shl128(x, s); return shr128(x, -s); #if 0 signed char left = (signed char) s; signed char right = -((signed char)(s >> 8) & left); return shl128(shr128(x, right), right + left); #endif } static inline bool test128(uint128_t x, int bit) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; x = shr128(x, bit); uuint128_t xx; xx.i128 = x; uint64_t u1 = xx.i64[0]; return u1 & 0x01; } static inline bool is_zero128(uint128_t x) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx; xx.i128 = x; uint64_t x1 = xx.i64[0]; uint64_t x2 = xx.i64[1]; return (x1 | x2) == 0; } static inline bool is_equal128(uint128_t x, uint128_t y) { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t xx, yy; xx.i128 = x; yy.i128 = y; uint64_t x1 = xx.i64[0]; uint64_t x2 = xx.i64[1]; uint64_t y1 = yy.i64[0]; uint64_t y2 = yy.i64[1]; return x1 == y1 && x2 == y2; } #endif #endif #endif SjaakII/include/bits32.h000644 000765 000024 00000004715 12452210627 016001 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BITS32_H #define BITS32_H #include #include "bool.h" #if defined _MSC_VER # include #endif static inline bool onebit32(uint32_t x) { return (x & (x-1)) == 0; } static inline int lsb32(uint32_t x) { #ifdef __GNUC__ return __builtin_ctz (x); #elif defined _MSC_VER unsigned long res; _BitScanForward(&res, x); return (int)res; #else int n = 0; assert(x); while ((x&((uint32_t)1<> 8) & left); return (x >> right) << (right + left); } static inline int bitscan32(uint32_t x) { #ifdef __GNUC__ return __builtin_ctz (x); #elif defined _MSC_VER unsigned long res; _BitScanForward(&res, x); return (int)res; #else int i = 0; assert(x); while (!(x & 1)) { i++; x >>= 1; } return i; #endif } /* Return the number of bits set on a bitboard * From http://chessprogramming.wikispaces.com/Population+Count */ static inline int popcount32(uint32_t x) { #ifdef __GNUC__ return __builtin_popcount(x); #else const uint32_t k1 = 0x55555555; const uint32_t k2 = 0x33333333; const uint32_t k4 = 0x0f0f0f0f; const uint32_t kf = 0x01010101; x = x - ((x >> 1) & k1); x = (x & k2) + ((x >> 2) & k2); x = (x + (x >> 4)) & k4; x = (x * kf) >> 24; return (int) x; #endif } #endif SjaakII/include/bits64.h000644 000765 000024 00000006534 12452210627 016007 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BITS64_H #define BITS64_H #include #include "bool.h" #if defined _MSC_VER # include # if !defined _M_AMD64 && !defined _M_X64 inline void _BitScanForward64(unsigned long *res, uint64_t b) { unsigned __int32 l, h; l = uint32_t(b & 0xffffffffu); h = uint32_t(b >> 32); if (l) { _BitScanForward(res, l); } else { _BitScanForward(res, h); *res += 32; } } inline void _BitScanReverse64(unsigned long *res, uint64_t b) { unsigned __int32 l, h; l = uint32_t(b & 0xffffffffu); h = uint32_t(b >> 32); if (h) { _BitScanReverse(res, h); *res += 32; } else { _BitScanReverse(res, l); } } #endif #endif static inline bool onebit64(uint64_t x) { return (x & (x-1)) == 0; } static inline int bitscan64(uint64_t x) { #ifdef __GNUC__ return __builtin_ctzll (x); #elif defined _MSC_VER unsigned long res; _BitScanForward64(&res, x); return (int)res; #else int i = 0; assert(x); while (!(x & 1)) { i++; x >>= 1; } return i; #endif } static inline int lsb64(uint64_t x) { #ifdef __GNUC__ return __builtin_ctzll (x); #elif defined _MSC_VER unsigned long res; _BitScanForward64(&res, x); return (int)res; #else int n = 0; assert(x); while ((x&((uint64_t)1<> 8) & left); return (x >> right) << (right + left); } static inline int bitscan16(uint16_t x) { #ifdef __GNUC__ return __builtin_ctz (x); #elif defined _MSC_VER unsigned long res; _BitScanForward(&res, x); return res; #else int i = 0; assert(x); while (!(x & 1)) { i++; x >>= 1; } return i; #endif } /* Return the number of bits set on a bitboard * From http://chessprogramming.wikispaces.com/Population+Count */ static inline int popcount64(uint64_t x) { #ifdef __GNUC__ return __builtin_popcountll(x); #else const uint64_t k1 = 0x5555555555555555ll; const uint64_t k2 = 0x3333333333333333ll; const uint64_t k4 = 0x0f0f0f0f0f0f0f0fll; const uint64_t kf = 0x0101010101010101ll; x = x - ((x >> 1) & k1); x = (x & k2) + ((x >> 2) & k2); x = (x + (x >> 4)) & k4; x = (x * kf) >> 56; return (int) x; #endif } #endif SjaakII/include/board.h000644 000765 000024 00000042633 12502304433 015756 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BOARD_H #define BOARD_H #include "compilerdef.h" #include "bitboard.h" #include "pieces.h" #include "piece_types.h" #include "move.h" #include "hashkey.h" #include "squares.h" /* Possible rule flags */ #define RF_FORCE_CAPTURE 0x00000001 #define RF_MULTI_CAPTURE 0x00000002 #define RF_KEEP_CAPTURE 0x00000004 /* Captured pieces go to your hand */ #define RF_RETURN_CAPTURE 0x00000008 /* Captured pieces go back to their owner's hand */ #define RF_USE_CAPTURE (RF_KEEP_CAPTURE | RF_RETURN_CAPTURE) #define RF_KING_TABOO 0x00000010 /* Kings cannot face eachother along a ray */ #define RF_KING_TRAPPED 0x00000020 /* Kings are trapped in a "palace" */ #define RF_KING_CORNERDRIVE 0x00000040 /* Kings can drive eachother from the corners */ #define RF_KING_DUPLECHECK 0x00000080 /* It's check if all kings are under attack, if there is more than one. */ #define RF_ALLOW_DROPS 0x00000100 /* The game allows drop moves */ #define RF_FORCE_DROPS 0x00000200 /* Drops are forced if possible */ #define RF_GATE_DROPS 0x00000400 /* Drops work as S-chess gates */ #define RF_USE_DROPS 0x00000700 /* Game uses drops */ #define RF_ALLOW_PICKUP 0x00000800 /* The player is allowed to take pieces in-hand */ #define RF_PROMOTE_IN_PLACE 0x00001000 /* Promotions can be done in-place, without moving a piece */ #define RF_PROMOTE_ON_DROP 0x00002000 /* Pieces can promote when they are dropped */ #define RF_SPECIAL_IS_INIT 0x00004000 /* Special moves are only initial moves */ #define RF_USE_HOLDINGS (RF_USE_DROPS | RF_USE_CAPTURE | RF_ALLOW_PICKUP) /* Game uses holdings in some way */ #define RF_USE_SHAKMATE 0x00010000 /* The checking sequence prior to mate needs particular pieces */ #define RF_USE_BARERULE 0x00020000 /* Shatranj-style baring rule */ #define RF_USE_CHASERULE 0x00040000 /* Xiangqi-style chase rule is in effect */ #define RF_CAPTURE_ANY_FLAG 0x00100000 /* There is a "capture the flag" victory condition. */ #define RF_CAPTURE_ALL_FLAG 0x00200000 /* There is a "capture the flag" victory condition. */ #define RF_CAPTURE_THE_FLAG (RF_CAPTURE_ANY_FLAG | RF_CAPTURE_ALL_FLAG) /* There is a "capture the flag" victory condition. */ /* Board state */ #define BF_CHECK 0x0001 /* Whether the side to move is in-check or not */ #define BF_WSHAK 0x0002 /* Whether a "shak" was given or not */ #define BF_BSHAK 0x0004 /* Whether a "shak" was given or not */ template struct unmake_info_t { bitboard_t init; bitboard_t ep; uint64_t board_hash; uint64_t hash; int8_t fifty_counter; int8_t ep_victim; uint8_t board_flags; uint8_t pickup_piece[4]; #ifdef DEBUGMODE move_t move; #endif }; template struct board_t { bitboard_t bbc[NUM_SIDES]; bitboard_t bbp[MAX_PIECE_TYPES]; bitboard_t flag[NUM_SIDES]; /* Flag bitboard, for "capture the flag" */ bitboard_t royal; bitboard_t init; bitboard_t ep; int8_t piece[8 * sizeof(kind)]; /* Piece holdings. * These are indexed by [piece type][side to move] * We actually have a rule flag to specify whether we're interested in these or not, so we can skip a chunk * of code for variants where we're not. */ int8_t holdings[MAX_PIECE_TYPES][NUM_SIDES]; /* Hash key */ uint64_t hash; uint64_t board_hash; /* Rule flags, to change the behaviour of the move generator or the evaluation function */ uint32_t rule_flags; /* Record the board state, in check, castle status */ uint8_t board_flags; /* En-passant target square and capture location. */ int8_t ep_victim; /* Half-move clock (50-move counter) */ int8_t fifty_counter; /* Side to move */ side_t side_to_move; /* Description of all piece types */ piece_description_t *piece_types; int virtual_files; int virtual_ranks; int bit_to_square[128]; bool check() const { return (board_flags & BF_CHECK); } void check(bool chk) { board_flags &= ~BF_CHECK; board_flags |= uint8_t(chk); if (!chk) board_flags &= ~(BF_WSHAK << side_to_move); } void shak() { board_flags |= (BF_WSHAK << side_to_move); } bool have_shak() { return (board_flags & (BF_WSHAK << side_to_move)) != 0; } void clear() { for (side_t side = WHITE; sidepiece_flags[type] & PF_ROYAL) royal.set(square); hash ^= piece_key[type][side][square]; board_hash ^= piece_key[type][side][square]; } void clear_piece(int type, side_t side, int square) { bbc[side].reset(square); bbp[type].reset(square); royal.reset(square); init.reset(square); hash ^= piece_key[type][side][square]; board_hash ^= piece_key[type][side][square]; } void put_new_piece(int type, side_t side, int square) { put_piece(type, side, square); init.set(square); } int8_t get_piece(int square) const { assert(square >= 0); assert(square < 8*sizeof(kind)); return piece[square]; } side_t get_side(int square) const { if (bbc[WHITE].test(square)) return WHITE; if (bbc[BLACK].test(square)) return BLACK; return NONE; } bitboard_t get_occupied() const { return bbc[WHITE] | bbc[BLACK]; } int piece_count(int piece, side_t side) const { return (bbc[side] & bbp[piece]).popcount(); } int locate_least_valued_piece(bitboard_t mask) const { int *perm = piece_types->val_perm; for (int n=0; nnum_piece_types; n++) { if (!(bbp[perm[n]] & mask).is_empty()) return (bbp[perm[n]] & mask).bitscan(); } return -1; } void makemove(move_t move, unmake_info_t *ui) { side_t swap_side[3]; int swap_piece[3]; int swap_to[3]; int n; /* First: backup information for unmake */ ui->init = init; ui->hash = hash; ui->board_hash = board_hash; ui->fifty_counter = fifty_counter; ui->ep = ep; ui->ep_victim = ep_victim; ui->board_flags = board_flags; #ifdef DEBUGMODE ui->move = move; #endif /* Second: resolve all pickups */ n = get_move_pickups(move); for (int c=0; cpickup_piece[c] = piece_for_side(piece, side); clear_piece(piece, side, square); } /* Third: resolve all swaps */ n = get_move_swaps(move); for (int c=0; c 0) hash ^= hold_key[piece][side][holdings[piece][side]]; } /* Sixth: update status bits */ ep_victim = 0; ep.clear(); if (move & MOVE_SET_ENPASSANT) { ep = bitboard_t::board_between[get_move_from(move)][get_move_to(move)]; ep_victim = get_move_to(move); } /* Seventh: flip side to move */ if (expect((move & MOVE_KEEP_TURN) == 0, true)) { side_to_move = next_side[side_to_move]; hash ^= side_to_move_key; board_hash ^= side_to_move_key; } /* Finally: update 50-move clock */ fifty_counter++; if (move & MOVE_RESET50) fifty_counter = 0; /* Assume we're not in check */ check(false); } void unmakemove(move_t move, unmake_info_t *ui) { side_t swap_side[3]; int swap_piece[3]; int swap_to[3]; int n; /* First: flip side to move */ if (expect((move & MOVE_KEEP_TURN) == 0, true)) side_to_move = next_side[side_to_move]; /* Second: reverse all drops */ n = get_move_drops(move); for (int c=0; cpickup_piece[c]); side_t side = side_for_piece(ui->pickup_piece[c]); put_piece(piece, side, square); } /* Fifth: update holdings */ if (expect((rule_flags & RF_USE_HOLDINGS) && get_move_holdings(move), false)) { uint16_t p = get_move_holding(move); int count = decode_holding_count(p); int piece = decode_holding_piece(p); side_t side = decode_holding_side(p); holdings[piece][side] -= count; assert(holdings[piece][side] >= 0); } /* Finally: restore backedup information */ init = ui->init; hash = ui->hash; board_hash = ui->board_hash; fifty_counter = ui->fifty_counter; ep = ui->ep; ep_victim = ui->ep_victim; board_flags = ui->board_flags; } void print(FILE* file = stdout, bitboard_t xmark = bitboard_t::board_empty, bitboard_t omark = bitboard_t::board_empty, bool ansi = true) const { const char *bg_colour_string[] = { "\033[45m", "\033[46m", "\033[44m" }; char mark[256]; int colour[256]; int pieces[256]; bool occupied[256]; side_t side[256]; bitboard_t occ = get_occupied(); int c, n; for (int r=0; r::board_ranks; r++) { for (int f=0; f::board_files; f++) { int bit = bitboard_t::pack_rank_file(r, f); int square = bit_to_square[bit]; if (square < 0) continue; colour[square] = ((square / virtual_files) ^ (square % virtual_files)) & 1; if (!bitboard_t::board_all.test(bit)) colour[square] = 2; if (omark.test(bit)) mark[square] ='*'; if (xmark.test(bit)) mark[square] ='+'; if (occ.test(bit)) { occupied[square] = true; side[square] = BLACK; if (bbc[WHITE].test(bit)) side[square] = WHITE; pieces[square] = get_piece(bit); } else { occupied[square] = false; } } } if (file != stdout) ansi = false; for (c=virtual_ranks-1; c>=0; c--) { if (ansi) fprintf(file, "%2s", rank_names[c]); if (ansi) fprintf(file, "\033[1m"); for (n=0; npiece_abbreviation[piece][1-white]); } else { if (ansi) fprintf(file, " %c", mark[square]); else fprintf(file, "%c%c", colour[square] ? '+' : '.', mark[square]); } } if (ansi) fprintf(file, "\033[0m"); if (side_to_move == BLACK && c == virtual_ranks-1) fprintf(file, "*"); if (side_to_move == WHITE && c == 0) fprintf(file, "*"); fprintf(file, "\n"); } if (ansi) { fprintf(file, " "); for (n=0; nnum_piece_types; n++) if (holdings[n][c]) fprintf(file, "%s: %02d ", piece_types->piece_abbreviation[n][c], holdings[n][c]); fprintf(file, "]\n"); } } } void print_bitboards() const { int c, n; if (side_to_move == WHITE) printf("White to move\n"); else printf("Black to move\n"); printf("White pieces\tBlack pieces\tUnmoved pieces\tRoyal\t\tep\t\tepc\n"); bitboard_t epbb, epcbb; epbb = ep; if (ep_victim) epcbb.set(ep_victim); for (c=bitboard_t::board_ranks-1; c>=0; c--) { printf("%s", bbc[0].rank_string(c)); printf("\t"); printf("%s", bbc[1].rank_string(c)); printf("\t"); printf("%s", init.rank_string(c)); printf("\t"); printf("%s", royal.rank_string(c)); printf("\t"); printf("%s", epbb.rank_string(c)); printf("\t"); printf("%s", epcbb.rank_string(c)); printf("\n"); } if (!piece_types) return; if (!flag[WHITE].is_empty() || !flag[BLACK].is_empty()) { printf("\nWhite flags\tBlack flags\n"); for (c=bitboard_t::board_ranks-1; c>=0; c--) { printf("%s", flag[WHITE].rank_string(c)); printf("\t"); printf("%s", flag[BLACK].rank_string(c)); printf("\n"); } } for (n=0; nnum_piece_types; n+=7) { printf("\n"); int k; for (k=0; k<7; k++) { if (n+k >= piece_types->num_piece_types) break; char *s = piece_types->piece_name[n+k]; printf("%*s", -bitboard_t::board_files-2, s); } printf("\n"); for (c=bitboard_t::board_ranks-1; c>=0; c--) { for (k=0; k<7; k++) { if (n+k >= piece_types->num_piece_types) break; printf("%s", bbp[n+k].rank_string(c)); printf(" "); } printf("\n"); } } if (rule_flags & RF_USE_HOLDINGS) { for (c=0; cnum_piece_types; n++) if (holdings[n][c]) printf("%s: %02d ", piece_types->piece_abbreviation[n][c], holdings[n][c]); printf("]\n"); } } } }; #endif SjaakII/include/board_rules.h000644 000765 000024 00000004143 12465213742 017174 0ustar00eglebbkstaff000000 000000 void add_rule(uint32_t rule) { board.rule_flags |= rule; } void remove_rule(uint32_t rule) { board.rule_flags &= ~rule; } void set_board_size(int files, int ranks) { assert(files*ranks <= 8*sizeof(kind)); initialise_square_names(files, ranks); bitboard_t::initialise_bitboards(files,ranks); movegen.initialise(); movegen.initialise_slider_tables(); this->ranks = ranks; this->files = files; top_left = files*(ranks-1); initialise_base_evaluation_tables(files, ranks); } void remove_square(int square) { bitboard_t bb = ~bitboard_t::square_bitboards[square]; int n; bitboard_t::board_all &= bb; bitboard_t::board_edge &= bb; bitboard_t::board_east_edge &= bb; bitboard_t::board_west_edge &= bb; bitboard_t::board_north_edge &= bb; bitboard_t::board_south_edge &= bb; bitboard_t::board_south &= bb; bitboard_t::board_north &= bb; bitboard_t::board_corner &= bb; bitboard_t::board_light &= bb; bitboard_t::board_dark &= bb; bitboard_t::board_centre &= bb; bitboard_t::board_xcentre &= bb; bitboard_t::board_xxcentre &= bb; bitboard_t::board_homeland[0] &= bb; bitboard_t::board_homeland[1] &= bb; for (n=0; n<16; n++) { bitboard_t::board_rank[n] &= bb; bitboard_t::board_file[n] &= bb; bitboard_t::board_northward[n] &= bb; bitboard_t::board_southward[n] &= bb; bitboard_t::board_eastward[n] &= bb; bitboard_t::board_westward[n] &= bb; } for (n=0; n<32; n++) { bitboard_t::board_diagonal[n] &= bb; bitboard_t::board_antidiagonal[n] &= bb; } int board_size = 8*sizeof(kind); for (int n=0; n::neighbour_board[n] &= bb; for (int k=0; k::board_between[n][k] &= bb; } } void place_flag(side_t side, int square) { board.flag[side].set(square); } void remove_flag(side_t side, int square) { board.flag[side].reset(square); } SjaakII/include/bool.h000644 000765 000024 00000000362 12452210627 015620 0ustar00eglebbkstaff000000 000000 #if defined(_MSC_VER) # include # if !defined __cplusplus // FIXME: hack # define inline typedef int bool; # define true 1 # define false 0 # endif #else # include #endif SjaakII/include/cfgpath.h000644 000765 000024 00000003022 12433144250 016272 0ustar00eglebbkstaff000000 000000 /** * @file cfgpath.h * @brief Cross platform methods for obtaining paths to configuration files. * * Copyright (C) 2013 Adam Nielsen * * This code is placed in the public domain. You are free to use it for any * purpose. If you add new platform support, please contribute a patch! * * Example use: * * char cfgdir[256]; * get_user_config_file(cfgdir, sizeof(cfgdir), "myapp"); * if (cfgdir[0] == 0) { * printf("Unable to find home directory.\n"); * return 1; * } * printf("Saving configuration file to %s\n", cfgdir); * * A number of constants are also defined: * * - MAX_PATH: Maximum length of a path, in characters. Used to allocate a * char array large enough to hold the returned path. * * - PATH_SEPARATOR_CHAR: The separator between folders. This will be either a * forward slash or a backslash depending on the platform. This is a * character constant. * * - PATH_SEPARATOR_STRING: The same as PATH_SEPARATOR_CHAR but as a C string, * to make it easier to append to other string constants. */ #ifndef CFGPATH_H_ #define CFGPATH_H_ #ifdef __cplusplus extern "C" { #endif extern void get_user_config_file(char *out, size_t maxlen, const char *appname); extern void get_user_config_folder(char *out, size_t maxlen, const char *appname); extern void get_user_data_folder(char *out, size_t maxlen, const char *appname); extern void get_user_cache_folder(char *out, size_t maxlen, const char *appname); #ifdef __cplusplus } #endif #endif /* CFGPATH_H_ */ SjaakII/include/chase.h000644 000765 000024 00000013433 12502304433 015746 0ustar00eglebbkstaff000000 000000 bitboard_t get_chased_pieces(int backtrack) { side_t chaser = next_side[board.side_to_move]; move_t last_move = 0; for (int n = 0; n<2*backtrack; n++) takeback(); if (moves_played) last_move = move_list[moves_played-1]; /* 1. Identify threats: * A "winning capture" is an up-capture, or an equal capture with SEE > 0 * A "threat move" is a winning capture, except for captures * - with the king * - with a pawn * - with a defensive piece * - of a pawn on the enemy side of the board * Discard pieces that are pinned - they cannot chase * * A threat move is a candidate chase. */ movelist_t chase_candidates, old_threats; movegen.generate_chase_candidates(&chase_candidates, &board, chaser); //printf("Threats:\n"); //chase_candidates.print(); /* Filter out old threats */ takeback(); movegen.generate_chase_candidates(&old_threats, &board, chaser); for (int n=0; npiece_capture_flags[n]; if (is_leaper(flags) && is_masked_leaper(flags)) { bitboard_t occ = board.get_occupied(); bitboard_t rev; rev = movegen.generate_leaper_move_bitboard(flags, board.side_to_move, cap, occ); if (rev.test(from)) chase_candidates.move[n--] = chase_candidates.move[--chase_candidates.num_moves]; /* No chase */ } else { chase_candidates.move[n--] = chase_candidates.move[--chase_candidates.num_moves]; /* No chase */ } } else { int to = get_move_to(move); bitboard_t revatk = movegen.get_all_attackers(&board, board.bbc[board.side_to_move], to); revatk &= board.royal; if (!revatk.is_empty()) chase_candidates.move[n--] = chase_candidates.move[--chase_candidates.num_moves]; /* No chase */ } } /* Identify chased pieces */ bitboard_t chased; for (int n=0; n 0); /* TODO */ int count = count_repetition(); //printf("Position repeated %d times\n", count); int backup = 0; for (int n=(int)moves_played-2; n>=0; n-=2) { //printf("%3d %016llx %016llx\n", n, ui[n].hash, board.hash); if (is_irreversible_move(move_list[n+1])) break; if (is_irreversible_move(move_list[n])) break; backup+=2; if (ui[n].hash == board.hash) break; } side_t chaser = next_side[board.side_to_move]; side_t chasee = board.side_to_move; bitboard_t chased_pieces[NUM_SIDES];// = board.bbc[board.side_to_move]; bool chasing[NUM_SIDES]; chased_pieces[WHITE] = board.bbc[WHITE]; chased_pieces[BLACK] = board.bbc[BLACK]; /* Get chased pieces on the current ply */ chased_pieces[chasee] = board.bbc[chasee]; for (int n = 0; n chased = get_chased_pieces(n); chased_pieces[chasee] &= chased; } chasing[chaser] = !chased_pieces[chasee].is_empty(); /* Other side */ takeback(); chased_pieces[chaser] = board.bbc[chaser]; for (int n = 0; n chased = get_chased_pieces(n); chased_pieces[chaser] &= chased; } replaymove(); move_t move = move_list[moves_played-1]; if ( chased_pieces[chaser].test(get_move_from(move)) ) { chased_pieces[chaser].reset(get_move_from(move)); chased_pieces[chaser].set(get_move_to(move)); } chasing[chasee] = !chased_pieces[chaser].is_empty(); /* If one side is evading check, then it cannot chase */ if (!(chased_pieces[WHITE] & board.royal).is_empty()) chasing[WHITE] = false; if (!(chased_pieces[BLACK] & board.royal).is_empty()) chasing[BLACK] = false; //printf("White chasing (%d)\n", chasing[WHITE]); //chased_pieces[BLACK].print(); //printf("Black chasing (%d)\n", chasing[BLACK]); //chased_pieces[WHITE].print(); if (chasing[WHITE] == chasing[BLACK]) return DRAW_CHASE; if (!chasing[board.side_to_move]) return WIN_CHASE; return LOSE_CHASE; } SjaakII/include/compilerdef.h000644 000765 000024 00000003353 12452237254 017166 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014, 2015 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMPILERDEF_H #define COMPILERDEF_H /* Various compiler-specific definitions and declarations. Mainly to deal * with differences between GNU and Microsoft compiler families. */ #if defined _MSC_VER # define _CRT_SECURE_NO_WARNINGS # define _CRT_NONSTDC_NO_WARNINGS # if !defined _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 0 # endif # define expect(x,y) (x) # define prefetch(x) (void)0 # define ATTRIBUTE_FORMAT_PRINTF # define ATTRIBUTE_ALIGNED(x) # define ATTRIBUTE_UNUSED # define PRIu64 "I64u" # if defined __cplusplus extern "C" { # endif int snprintf(char *buf, size_t size, const char *fmt, ...); # if defined __cplusplus } # endif #else /* Assume GNU */ # include # define expect(x,y) __builtin_expect((x), (y)) # define prefetch(x) __builtin_prefetch(x) # define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(printf, 1, 2))) # define ATTRIBUTE_ALIGNED(x) __attribute__((aligned(x))) # define ATTRIBUTE_UNUSED __attribute__((unused)) #endif #endif SjaakII/include/eval_param.h000644 000765 000024 00000006276 12502304433 017001 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define SAFE_MOB_WEIGHT 8 // Weight for safe mobility squares #define MOB_SCALE 16 // Overall mobility weight #define MOB_FORWARD_BLOCKED 5 // Penalty for forward mobility blocked by pieces #define KS_ATTACK_WEIGHT 256 #define KS_SHELTER_WEIGHT 32 #define KING_SAFETY_WEIGHT 416 // Overall scale-factor for king safety // Weight vs. STS score: // 512 (3126) // 256 (3044) // 384 (3118) // 448 (3117) // 416 (3128) #define PST_HOLDINGS 5 // PST value for a piece in holdings #define PST_SPACE_MG 5 // PST value for empty squares on the own side of the board #define PASSER_RANK_SCALE 4 #define PAWN_ADVANCE_Q_EG 98.0 // Bonus for advancing pawns in the end game, quadratic term #define PAWN_ADVANCE_L_EG 0.0 // Bonus for advancing pawns in the end game, linear term #define PAWN_ADVANCE_Q_MG 0.0 // Bonus for advancing pawns in the middle game, quadratic term #define PAWN_ADVANCE_L_MG 0.0 // Bonus for advancing pawns in the middle game, linear term #define ROOK_BASE_PAWN_MG 5 // Bonus for a rook that attacks base of enemy pawn structure, middle game #define ROOK_BASE_PAWN_EG 10 // Bonus for a rook that attacks base of enemy pawn structure, end game #define WEAK_PAWN_BASE_MG 5 // Penalty for a weak pawn, middle game #define WEAK_PAWN_BASE_EG 10 // Penalty for a weak pawn, end game #define LOOSE_MINOR_PENALTY 5 // Penalty for an undefended minor on the enemy side of the board #define PAIR_BONUS_MG 0.10 // Fraction of piece value #define PAIR_BONUS_EG 0.15 // Fraction of piece value #define SLIDER_OPENFILE_MG 10 // Slider bonus on open file, middle game #define SLIDER_OPENFILE_EG 15 // Slider bonus on open file, end game #define DEF_PROTECT 7 // Bonus for defensive pieces that protect eachother #define DEF_SHIELD_FILE 10 // Bonus for defensive pieces on king file #define FUTILITY_DEPTH 3 #define PAWN_SCALE_MG 0.8 // Fraction of nominal piece value #define LAME_SCALE_MG 0.9 // Fraction of nominal piece value #define LAME_SCALE_EG 1.1 // Fraction of nominal piece value #define DEF_SCALE_MG 1.1 // Fraction of nominal piece value #define DEF_SCALE_EG 0.8 // Fraction of nominal piece value #define HOP_SCALE_EG 0.7 // Fraction of nominal piece value SjaakII/include/eval_types.h000644 000765 000024 00000007756 12464173015 017060 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EVAL_TYPES_H #define EVAL_TYPES_H #include "compilerdef.h" typedef int16_t eval_t; struct eval_pair_t { eval_t mg, eg; eval_pair_t () { mg = eg = 0; } eval_pair_t (int v) { mg = eg = v; } eval_pair_t (int m, int e) { mg = m; eg = e; } inline eval_pair_t operator = (const eval_pair_t p) { mg = p.mg; eg = p.eg; return *this; } inline eval_pair_t operator = (const int v) { mg = v; eg = v; return *this; } inline eval_pair_t operator << (const int bits) const { return eval_pair_t(mg << bits, eg << bits); } inline eval_pair_t operator >> (const int bits) const { return eval_pair_t(mg >> bits, eg >> bits); } inline eval_pair_t operator +=(const eval_pair_t &rhs) { mg += rhs.mg; eg += rhs.eg; return *this; } inline eval_pair_t operator -=(const eval_pair_t &rhs) { mg -= rhs.mg; eg -= rhs.eg; return *this; } inline eval_pair_t operator *=(const eval_pair_t &rhs) { mg *= rhs.mg; eg *= rhs.eg; return *this; } inline eval_pair_t operator /=(const eval_pair_t &rhs) { mg /= rhs.mg; eg /= rhs.eg; return *this; } inline eval_pair_t operator +=(const int &rhs) { mg += rhs; eg += rhs; return *this; } inline eval_pair_t operator -=(const int &rhs) { mg -= rhs; eg -= rhs; return *this; } inline eval_pair_t operator *=(const int &rhs) { mg *= rhs; eg *= rhs; return *this; } inline eval_pair_t operator /=(const int &rhs) { mg /= rhs; eg /= rhs; return *this; } inline const eval_pair_t operator +(const eval_pair_t &rhs) const { return eval_pair_t(*this) += rhs; } inline const eval_pair_t operator -(const eval_pair_t &rhs) const { return eval_pair_t(*this) -= rhs; } inline const eval_pair_t operator *(const eval_pair_t &rhs) const { return eval_pair_t(*this) *= rhs; } inline const eval_pair_t operator /(const eval_pair_t &rhs) const { return eval_pair_t(*this) /= rhs; } inline const eval_pair_t operator +(const int &rhs) const { return eval_pair_t(*this) += eval_pair_t(rhs); } inline const eval_pair_t operator -(const int &rhs) const { return eval_pair_t(*this) -= eval_pair_t(rhs); } inline const eval_pair_t operator *(const int &rhs) const { return eval_pair_t(*this) *= eval_pair_t(rhs); } inline const eval_pair_t operator /(const int &rhs) const { return eval_pair_t(*this) /= eval_pair_t(rhs); } inline const eval_pair_t operator *(const float &rhs) const { return eval_pair_t(this->mg * rhs, this->eg * rhs); } inline eval_t interpolate(int x, int scale) const { //if (x < 0) x = 0; //if (x > scale) x = scale; if (expect(scale == 0, false)) return mg; return (scale * mg + (scale - x) * (eg-mg) ) / scale; } inline eval_pair_t operator -() const { return eval_pair_t(-mg, -eg); } }; /* Pawn structure tables */ template struct pawn_structure_t { bitboard_t open; bitboard_t passed; bitboard_t stop; bitboard_t weak; bitboard_t attacked[NUM_SIDES]; eval_t shelter_score[NUM_SIDES][16]; }; #endif SjaakII/include/evalhash.h000644 000765 000024 00000002573 12452210627 016466 0ustar00eglebbkstaff000000 000000 /* Leonidas, a program for playing chess variants * Copyright (C) 2009, 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EVALHASH_H #define EVALHASH_H #ifdef __cplusplus extern "C" { #endif #include #include "bool.h" #undef DEBUG_EVHASH typedef struct { #ifdef DEBUG_EVHASH uint64_t key; #endif uint64_t data; } eval_hash_t; typedef struct { eval_hash_t *data; size_t number_of_elements; } eval_hash_table_t; eval_hash_table_t *create_eval_hash_table(size_t nelem); void destroy_eval_hash_table(eval_hash_table_t *table); bool query_eval_table_entry(eval_hash_table_t *table, uint64_t key, int16_t *score); void store_eval_hash_entry(eval_hash_table_t *table, uint64_t key, int16_t score); #ifdef __cplusplus } #endif #endif SjaakII/include/evaluate.h000644 000765 000024 00000071023 12477662023 016505 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if 0 struct pawn_structure_t { bitboard_t open; bitboard_t passed; bitboard_t stop; bitboard_t weak; bitboard_t attacked[NUM_SIDES]; }; #endif template void game_template_t::calculate_pawn_structure(pawn_structure_t *ps) { bitboard_t passed; bitboard_t stop; bitboard_t open; bitboard_t weak; bitboard_t pawns; open = bitboard_t::board_all; memset(ps, 0, sizeof *ps); for (side_t side=WHITE; side bb = pawns & board.bbc[side]; bitboard_t ob = pawns & ~board.bbc[side]; /* Shelter score (0-8) */ for (int f = 0; f::board_files; f++) { int lf = (f == 0) ? f+1 : f-1; int rf = (f == files-1) ? f-1 : f+1; int r = 0; if (side == BLACK) r = bitboard_t::board_ranks-1; int square = pack_rank_file(r, f); bitboard_t mask1 = bitboard_t::neighbour_board[square]; bitboard_t mask2 = bitboard_t::king_zone[side][square] ^ mask1; bitboard_t mask3 = bitboard_t::board_file[f]; bitboard_t mask4 = bitboard_t::board_file[lf]; bitboard_t mask5 = bitboard_t::board_file[rf]; if (!(bb & mask1 & mask3).is_empty()) ps->shelter_score[side][f] += 4; else if (!(bb & mask2 & mask3).is_empty()) ps->shelter_score[side][f] += 2; if (!(bb & mask1 & mask4).is_empty()) ps->shelter_score[side][f] += 2; else if (!(bb & mask2 & mask4).is_empty()) ps->shelter_score[side][f] += 1; if (!(bb & mask1 & mask5).is_empty()) ps->shelter_score[side][f] += 2; else if (!(bb & mask2 & mask5).is_empty()) ps->shelter_score[side][f] += 1; } /* Identify passers, open files, candidate weak pawns */ bitboard_t bp = bb; while(!bp.is_empty()) { int square = bp.bitscan(); bp.reset(square); if (pt.piece_promotion_choice[pt.pawn_index[side]] && (pt.passer_mask[side][square] & ob).is_empty()) passed.set(square); open &= ~bitboard_t::board_file[unpack_file(square)]; if (!pt.weak_mask[side][square].is_empty() && (pt.weak_mask[side][square] & bb).is_empty()) weak.set(square); } } ps->passed = passed; ps->open = open; ps->stop = stop; ps->weak = weak; } template template eval_t game_template_t::static_evaluation(side_t side_to_move, int /* alpha */, int /* beta */) { bitboard_t moves[8*sizeof(kind)]; bitboard_t attack[8*sizeof(kind)]; bitboard_t less_attacks[NUM_SIDES][MAX_PIECE_TYPES]; bitboard_t attacks[NUM_SIDES][MAX_PIECE_TYPES]; bitboard_t all_attacks[NUM_SIDES]; bitboard_t multi_attacks[NUM_SIDES]; bitboard_t pawn_attacks[NUM_SIDES]; bitboard_t pawns[NUM_SIDES]; bitboard_t minors[NUM_SIDES]; bitboard_t occ = board.get_occupied(); bitboard_t defence, castle; bitboard_t defatk; pawn_structure_t ps; bool can_win[NUM_SIDES] = { false, false }; int mate_potential[NUM_SIDES] = { 0, 0 }; int num_pieces[NUM_SIDES] = { 0, 0 }; int num_royals[NUM_SIDES] = { 0, 0 }; int num_pawns[NUM_SIDES] = { 0, 0 }; int num_supers[NUM_SIDES] = { 0, 0 }; int num_def[NUM_SIDES] = { 0, 0 }; int num_light_bound[NUM_SIDES]= { 0, 0 }; int num_dark_bound[NUM_SIDES] = { 0, 0 }; uint32_t piece_ids[NUM_SIDES] = { 0, 0 }; int square_list[8*sizeof(kind)] = {0}, square_count = 0; int king[NUM_SIDES] = { -1, -1 }; int shelter[2] = {0, 0}; eval_pair_t def[2] = { 0, 0 }; // Defensive pieces eval_pair_t mat = 0; // Material balance eval_pair_t psq = 0; // Piece square tables eval_pair_t mob = 0; // Mobility eval_pair_t pss = 0; // Pawn structure score eval_pair_t kss = 0; // King safety score eval_t ev = 0; eval_t hash_ev = 0; int phase = 0; bool symmetric = true; bool have_eval_hash = query_eval_table_entry(eval_table, board.hash, &hash_ev); #ifndef DEBUG_EVHASH if (have_eval_hash && !print) { ev = hash_ev; goto exit; } #endif calculate_pawn_structure(&ps); for (side_t side = WHITE; side less_attack; /* Accumulate attack bitmask of pieces less valuable than the current piece. */ if (board.rule_flags & RF_CAPTURE_ALL_FLAG) { int flag_count = board.flag[side].popcount(); int cflag_count = (board.flag[side] & board.bbc[side]).popcount(); if (flag_count) { psq += 5 * cflag_count*cflag_count / flag_count; } } /* Evaluate pieces and collect mobility and attack information. * Do the pieces in order of increasing value, so we can do safe * mobility. */ int gate_space = 0; if (board.rule_flags & RF_GATE_DROPS) { for (int n=0; n::board_homeland[side] & ~occ).popcount(); for (int n=0; n bb = board.bbc[side] & board.bbp[piece]; if (board.rule_flags & RF_GATE_DROPS) { if (gate_space) { int gate_scale = files*(files-1); int gate_score = (board.init & ~board.royal & board.bbc[side] & (bitboard_t::board_south_edge | bitboard_t::board_north_edge)).popcount(); int pst = PST_HOLDINGS; float scale = (float)gate_score*(gate_score-1) / gate_scale; if (gate_score > gate_space+2) { scale = 1.0; phase += pt.phase_weight[piece] * board.holdings[piece][side]; } else if (gate_score >= gate_space) { gate_scale = gate_score*(gate_score-1) + 1; scale = (float)gate_score*(gate_score-1) / gate_scale; phase += pt.phase_weight[piece] * board.holdings[piece][side]; pst = 0; } else { phase += pt.phase_weight[piece] * board.holdings[piece][side] * scale; pst = 0; } mat += pt.eval_value[piece] * board.holdings[piece][side] * scale; psq += pst * board.holdings[piece][side] * scale; } } else { mat += pt.eval_value[piece] * board.holdings[piece][side]; psq += PST_HOLDINGS * board.holdings[piece][side]; } if (bb.is_empty()) continue; if (!(pt.piece_flags[piece] & PF_ROYAL)) piece_ids[side] |= 1<::board_light).is_empty() && !(bb & bitboard_t::board_dark).is_empty()) mat += pt.eval_pair_bonus[piece]; else if ( (pt.defensive_pieces & (1 << piece)) && !bb.onebit()) mat += pt.eval_pair_bonus[piece]; } /* Piece square tables/material evaluation */ while(!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); square_list[square_count++] = square; if (pt.defensive_pieces & (1<::board_homeland[side] & pt.prison[side][piece]; } if (pt.piece_flags[piece] & PF_COLOURBOUND) { if (bitboard_t::board_light.test(square)) num_light_bound[side]++; else num_dark_bound[side]++; } if (!(pt.piece_flags[piece] & PF_CANTMATE)) mate_potential[side]++; moves[square] = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[piece], square, occ, side); /* Collect attack bitmasks * TODO: for pawns it is more efficient to do this for all pawns * at once (in bulk) after the loop is done. */ bitboard_t atk = moves[square]; if (pt.piece_move_flags[piece] != pt.piece_capture_flags[piece]) atk = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[piece], square, occ, side); multi_attacks[side] |= all_attacks[side] & atk; attacks[side][piece] |= atk; all_attacks[side] |= atk; attack[square] = atk; if (pt.defensive_pieces & (1< 0) mat.mg = std::max(0, mat.mg - def[BLACK].mg/2); if (mat.eg > 0) mat.eg = std::max(0, mat.eg - def[BLACK].eg/2); /* Gather data for shelter and assess winning chances. */ for (side_t side = WHITE; side= 0); int piece = board.get_piece(king[side]); eval_t score = 0; eval_t cscore = 0; int f = unpack_file(king[side]); score = ps.shelter_score[side][f]; /* 0-8 */ shelter[side] = 4*score; /* 0-32 */ if ((board.init & movegen.castle_mask[SHORT][side] & board.bbc[side]) == movegen.castle_mask[SHORT][side]) { int square = movegen.castle_king_dest[SHORT][side]; int f = unpack_file(square); cscore = std::max(cscore, ps.shelter_score[side][f]); } if ((board.init & movegen.castle_mask[LONG][side] & board.bbc[side]) == movegen.castle_mask[LONG][side]) { int square = movegen.castle_king_dest[LONG][side]; int f = unpack_file(square); cscore = std::max(cscore, ps.shelter_score[side][f]); } //printf("Shelter: %d %d\n", score, cscore); if (cscore > score) score = (score + cscore) / 2; kss.mg += 4*score; /* Defensive pieces */ if ( !(defence & castle).is_empty() ) { eval_t score = 0; score += 2*(bitboard_t::board_file[f] & defence & castle & bitboard_t::board_homeland[side]).popcount(); score += ((bitboard_t::board_file[f-1]|bitboard_t::board_file[f+1]) & defence & castle & bitboard_t::board_homeland[side]).popcount(); score += (defatk & castle).popcount(); score += (defatk & defence & castle).popcount(); shelter[side] = std::min(2*score, KS_SHELTER_WEIGHT); kss.mg += shelter[side]; } /* Shelter score for drop-games */ if ( pt.defensive_pieces == 0 && (board.rule_flags & RF_USE_CAPTURE) ) { bitboard_t king_zone = bitboard_t::neighbour_board[king[side]]; eval_t score = 0; score = ps.shelter_score[side][f]; score += 2*(king_zone & board.bbc[side]).popcount(); score += (king_zone & less_attacks[side][piece]).popcount(); shelter[side] = std::min(1*score, KS_SHELTER_WEIGHT); if ((king_zone & (multi_attacks[oside]|(all_attacks[oside]&~less_attacks[side][piece]))).is_empty()) shelter[side] /= 2; kss.mg += shelter[side] / 2; } } /* King safety */ /* TODO */ /* Winning chances * TODO: test if pawns can promote to something with mate potential. */ if (mate_potential[side] >= 1) can_win[side] = true; else { int non_pawn_non_royal = num_pieces[side]-num_pawns[side]-num_royals[side] - num_def[side]; if (num_pawns[side] >= 1 || non_pawn_non_royal > 2) can_win[side] = true; if (non_pawn_non_royal == 2 && !can_win[side]) { uint32_t p = piece_ids[side]; int n1, n2; n1 = n2 = bitscan32(p); p ^= 1< bb = board.bbp[oside]; while (!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); int score = (ranks + files)/2 - pt.tropism[piece][king[side]][square]; psq += 4*score*abs(score); } psq += 8*(all_attacks[side] & ~all_attacks[oside]).popcount(); int weight = num_light_bound[oside] - num_dark_bound[oside]; for (int n = 0; n<2; n++) { if (weight > 0) { bitboard_t avoid = (n == 0 ? bitboard_t::board_light : bitboard_t::board_dark ) & bitboard_t::board_corner; while (!avoid.is_empty()) { int square = avoid.bitscan(); avoid.reset(square); int score = (ranks + files)/2 - pt.tropism[piece][king[side]][square]; psq -= 2*weight * score * abs(score); psq += 1*abs(centre_table[king[side]]) * centre_table[king[side]] - 3*abs(centre_table[king[oside]])* centre_table[king[oside]]; psq -= pt.tropism[piece][king[oside]][square]/2; } } weight = -weight; } } } /* Flip evaluation values for side to move. * Idea from Senpai. */ psq = -psq; kss = -kss; pss = -pss; } /* Draw-ish material combinations */ if (num_pawns[WHITE] == 0 && num_pawns[BLACK] == 0) { if (mate_potential[WHITE] == mate_potential[BLACK] && mate_potential[WHITE] == 1 && abs(num_pieces[WHITE]-num_pieces[BLACK]) <= 1) mat /= 4; if (num_pieces[WHITE] == num_pieces[BLACK] && num_pieces[WHITE] == 1 && mate_potential[WHITE]+mate_potential[BLACK] == 1) mat /= 8; } /* Mobility, piece safety */ { int wa_weight[NUM_SIDES][8*sizeof(kind)] = { { 0 } }; int wa_count[NUM_SIDES][8*sizeof(kind)] = { { 0 } }; int si = 0; for (side_t side = WHITE; side king_zone; side_t oside = next_side[side]; if (num_royals[oside] == 1) { king_zone = bitboard_t::king_zone[oside][king[oside]]; if ( board.rule_flags & RF_USE_HOLDINGS ) { for (int piece = 0; piece wpa = attack[square] & ps.weak; while (!wpa.is_empty()) { int square = wpa.bitscan(); wpa.reset(square); wa_weight[side][square] += std::max(1, pt.phase_weight[piece]); wa_count[side][square]++; } /* Attack on base of pawn structure */ if ((pt.major_pieces & (1<::board_ranks - 1) - rank; eval_t scale = PASSER_RANK_SCALE; bitboard_t fs = pt.front_span[side][square]; if ((fs & occ).is_empty()) scale++; fs.set(square); if (all_attacks[side].test(square)) scale++; if ((fs & all_attacks[side]) == fs) scale++; if ((fs & all_attacks[oside]).is_empty()) scale++; pss.eg += scale*rank*rank; } } /* Kings should stay put until the end game, so don't score king * mobility in the middle game. */ if (pt.piece_flags[piece] & PF_ROYAL) { bitboard_t safe = moves[square] & ~all_attacks[oside]; bitboard_t unsafe = moves[square] ^ safe; mob.eg += pt.eval_mobility[piece][safe.popcount()].eg * SAFE_MOB_WEIGHT / 128; } else { bitboard_t up_attacks = all_attacks[oside] ^ less_attacks[oside][piece]; bitboard_t safe = (moves[square] & ~less_attacks[oside][piece]) | (moves[square] & up_attacks & all_attacks[side]); bitboard_t unsafe = moves[square] ^ safe; mob += pt.eval_mobility[piece][safe.popcount()] * SAFE_MOB_WEIGHT / 128; bitboard_t forward = (side == WHITE) ? bitboard_t::board_northward[unpack_rank(square)] : bitboard_t::board_southward[unpack_rank(square)]; if ((moves[square] & forward & ~pawns[side]).is_empty()) psq.mg -= MOB_FORWARD_BLOCKED; } /* Board control * Important squares to control in the middle game are in the * centre and the opponent side of the board. * In the end game focus changes to pawns and blocking passers. */ bitboard_t control = attack[square] & ~pawn_attacks[oside]; int cw = 0; if ( pt.minor_pieces & (1 << piece) ) cw = 4; if ( pt.major_pieces & (1 << piece) ) cw = 2; if ( pt.super_pieces & (1 << piece) ) cw = 1; eval_t score = 3*(control & bitboard_t::board_centre).popcount() + 2*(control & bitboard_t::board_xcentre).popcount() + 1*(control & bitboard_t::board_xxcentre).popcount() + 1*(control & bitboard_t::board_homeland[oside]).popcount(); mob.mg += MOB_SCALE * cw * (score - 4); if ( pt.royal_pieces & (1 << piece) ) cw = 4; mob.eg += MOB_SCALE * cw * 4 * (control & (ps.weak | ps.passed) & board.bbc[side]).popcount(); /* Piece placement */ if (pt.minor_pieces & (1<::board_edge & bitboard_t::board_homeland[oside]).test(square) ) { // psq.mg += 5; //} } /* In the end game the king should move towards enemy pawns */ /* TODO */ /* Defensive pieces should defend eachother * By definition, defensive pieces cannot attack squares on the * opponent's side of the board, so if they are ever attacked, * it's by one of their own pieces. */ if (pt.defensive_pieces & (1<::board_rank[rank]).is_empty()) psq += DEF_SHIELD_FILE; } si++; } /* King attack pattern: the (safe) attack count causes the score * to increase exponentially, while a good shelter causes it to * decrease linearly. The exact form of the expression is * based on Senpai's implementation of the idea. * TODO: tune the overall constant scale factor. */ assert(KS_SHELTER_WEIGHT - shelter[oside] >= 0); ka_weight *= (KS_ATTACK_WEIGHT - (KS_ATTACK_WEIGHT >> ka_count)) * (KS_SHELTER_WEIGHT - shelter[oside]); if (ka_scale) kss.mg += KING_SAFETY_WEIGHT * ka_weight / ka_scale; mob = -mob; psq = -psq; kss = -kss; pss = -pss; } /* Pressure against weak pawns */ for (side_t side = WHITE; side wp = ps.weak & board.bbc[side]; while (!wp.is_empty()) { int square = wp.bitscan(); wp.reset(square); int weight = (8 - (8 >> wa_count[oside][square])) * std::max(0, 8 - wa_count[side][square]); pss -= base; pss -= base * weight / 64; } pss = -pss; } mob /= MOB_SCALE; assert(si == square_count); } done: if (print) { printf("Component: MG: EG:\n"); printf("Material: % 4d % 4d\n", mat.mg, mat.eg); printf("Piece square: % 4d % 4d\n", psq.mg, psq.eg); printf("Mobility: % 4d % 4d\n", mob.mg, mob.eg); printf("Pawn structure: % 4d % 4d\n", pss.mg, pss.eg); printf("King safety: % 4d % 4d\n", kss.mg, kss.eg); } /* Disable phase-scaling in variants where captured pieces are returned: * there material does not represent game phase. */ if (board.rule_flags & RF_USE_CAPTURE) phase = pt.phase_scale; /* Interpolate evaluation score. */ ev = (mat + psq + mob + pss + kss).interpolate(phase, pt.phase_scale); /* Adjust the score: if the side that is nominally ahead can't win, drop the score to 0(ish) */ phase = std::min(phase, pt.phase_scale); if (!can_win[WHITE] && !can_win[BLACK]) ev = 0; if (ev > 0 && !can_win[WHITE]) { symmetric = false; ev = psq.interpolate(phase, pt.phase_scale); } if (ev < 0 && !can_win[BLACK]) { symmetric = false; ev = psq.interpolate(phase, pt.phase_scale); } #ifdef DEBUG_EVHASH /* Sanity check: the hashed score should equal the current score. * We only ever get here if we're debugging the evaluation hash. */ if (symmetric) { if (!(!have_eval_hash || (hash_ev == ev))) { printf("%d %d %d %d\n", have_eval_hash, hash_ev, ev, symmetric); printf("0x%016llx\n", board.hash); board.print_bitboards(); //printf("%s\n", make_fen_string(game, NULL)); } assert(!have_eval_hash || (hash_ev == ev)); } #endif /* Store the results of the evaluation in the evaluation hash table. * If the evaluation is symmetric, we can store it for the other side * to move as well, which will safe an evaluation after null-move. */ store_eval_hash_entry(eval_table, board.hash, ev); if (symmetric) store_eval_hash_entry(eval_table, side_to_move_key^board.hash, ev); exit: /* Tapered evaluation when we're about to hit the 50 move counter */ if (board.fifty_counter > 80) ev = ev * (101 - board.fifty_counter) / 20; return (side_to_move == WHITE) ? ev : -ev; } SjaakII/include/fen.h000644 000765 000024 00000031625 12502304433 015436 0ustar00eglebbkstaff000000 000000 void record_castle_state(char state, bitboard_t *castle_init) { /* Deal with different type of castle flags */ int board_files = bitboard_t::board_files; int board_ranks = bitboard_t::board_ranks; int rook_file = -1; int rook_from = -1; if (state == '-') return; if (!isalpha(state)) return; side_t side = BLACK; if (isupper(state)) side = WHITE; char file_char = (side == WHITE) ? 'A' : 'a'; if (state-file_char < board_files) { rook_file = state - file_char; rook_from = bitboard_t::pack_rank_file( (side == WHITE) ? 0 : (board_ranks-1), rook_file); castle_init->set(rook_from); if (board.rule_flags & RF_GATE_DROPS) return; } switch(state) { case 'K': /* Starting at the right edge of the board, find the first castle * piece. */ state = '-'; for (int n = board_files - 1; n>=0; n--) { if (board.get_piece(n) == pt.castle_piece[side][SHORT]) { rook_from = n; state = file_char + n; break; } } if (state != 'K') record_castle_state(state, castle_init); break; case 'Q': /* Starting at the left edge of the board, find the first castle * piece. */ state = '-'; for (int n = 0; n=0; n--) { int s = board_files * (board_ranks-1); if (board.get_piece(s + n) == pt.castle_piece[side][SHORT]) { rook_from = s+n; state = file_char + n; break; } } if (state != 'k') record_castle_state(state, castle_init); break; case 'q': /* Starting at the left edge of the board, find the first castle * piece. */ state = '-'; for (int n = 0; n= unpack_file(king_from)) castle_side = SHORT; king_to = movegen.castle_king_dest[castle_side][side]; //printf("%d (%s %s) (%s)\n", side, square_names[king_from], square_names[king_to], square_names[rook_from]); movegen.deduce_castle_flags(side, king_from, king_to, rook_from); castle_init->set(king_from); return; } void setup_fen_position(const char *str, bool skip_castle = false) { const char *s = str; int prev_rank = 2*bitboard_t::board_files; int square = top_left; int n; if (!s) return; moves_played = 0; board.clear(); memset(repetition_hash_table, 0, sizeof repetition_hash_table); memset(board_repetition_hash_table, 0, sizeof board_repetition_hash_table); /* Parse first record: piece positions */ while(*s && (*s != ' ') && (*s != '[') && square>=0) { switch (*s) { case '/': square -= prev_rank; break; case '*': square++; break; case '1': if (isdigit(s[1])) { square += 10; break; } case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': square += (*s - '1')+1; break; default: side_t side = NONE; int piece = -1; int best_len = 0; for (n=0; n best_len) { best_len = len; side = match_side; piece = n; } } } if (piece == -1) { if (error_output) error_output("Error: unknown piece type '%c' (bad FEN %s)\n", *s, str); return; } assert(side != NONE); assert(square_to_bit[square] >= 0); board.put_new_piece(piece, side, square_to_bit[square]); s += strlen(pt.piece_abbreviation[piece][side])-1; square++; break; } s++; } /* Optional: check for holdings */ while(*s && (*s == ' ')) s++; if (*s == '[') { s++; while (*s != ']') { for (n=0; n castle_init; if (!skip_castle) record_castle_state(*s, &castle_init); s++; board.init |= castle_init; } if (*s) s++; } /* Make sure the initial flags are at least somewhat sane by making sure only occupied squares have their * init bits set. */ board.init &= board.get_occupied(); /* Fourth record: En-passant square * If this record is a number, then the game doesn't have en-passant capture and we skip it. */ while(*s && (*s == ' ')) s++; if (!isdigit(*s)) { if (*s && (*s != '-')) { int file = *s - 'a'; int rank = s[1] - '1'; s+=2; /* En-passant move-to square */ board.ep.set(bitboard_t::pack_rank_file(rank, file)); /* En-passant capture square, this may be encoded in the FEN */ if (!isspace(*s)) { int file = *s - 'a'; int rank = s[1] - '1'; s+=2; board.ep_victim = bitboard_t::pack_rank_file(rank, file); } else { /* Assume we have normal pawns, in which case we can simply derive it from the move-to square */ if (board.side_to_move == WHITE) board.ep_victim = board.ep.bitscan() - bitboard_t::board_files; else board.ep_victim = board.ep.bitscan() + bitboard_t::board_files; } } while(*s && (*s != ' ')) s++; } /* Fifth record: half-move counter (50 move counter) */ while(*s && (*s == ' ')) s++; n = 0; sscanf(s, "%d\n", &n); board.fifty_counter = n; while(*s && (*s != ' ')) s++; /* Sixth record: full-move counter */ while(*s && (*s == ' ')) s++; n = 0; sscanf(s, "%d\n", &n); start_move_count = 2*std::max(0, n-1); while(*s && (*s != ' ')) s++; repetition_hash_table[board.hash&0xFFFF] = 1; board_repetition_hash_table[board.board_hash&0xFFFF] = 1; /* Record check state */ board.check(player_in_check(board.side_to_move)); } const char *make_fen_string(char *buffer = NULL) const { static char static_buffer[4096]; bitboard_t occ; char *fen = buffer; int n = 0; int r, f; if (!fen) fen = static_buffer; fen[0] = '\0'; occ = board.bbc[WHITE] | board.bbc[BLACK]; /* First record: board position */ /* Scan all ranks */ for (r = board.virtual_ranks-1; r>=0; r--) { int count = 0; for (f = 0; f < board.virtual_files; f++) { int square = f + r*board.virtual_files; int bit = square_to_bit[square]; if (bit < 0 || bit_to_square[bit] < 0 || !bitboard_t::board_all.test(bit)) { if (count) n += snprintf(fen+n, 4096 - n, "%d", count); count = 0; n += snprintf(fen+n, 4096-n, "*"); continue; } /* Empty? */ if (!occ.test(bit)) { count++; continue; } /* Not empty, do we have a count? */ if (count) n += snprintf(fen+n, 4096 - n, "%d", count); count = 0; /* Print piece */ side_t side = board.get_side(bit); int piece = board.get_piece(bit); n += snprintf(fen+n, 4096-n, "%s", pt.piece_abbreviation[piece][side]); } if (count) n += snprintf(fen+n, 4096 - n, "%d", count); if (r) n += snprintf(fen+n, 4096 - n, "/"); } /* Holdings */ if (board.rule_flags & RF_USE_HOLDINGS) { n += snprintf(fen+n, 4096 - n, "["); bool empty = true; for (side_t side = WHITE; side <= BLACK; side++) { for (int piece = 0; piece < pt.num_piece_types; piece++) { for (int count = 0; count < board.holdings[piece][side]; count++) { empty = false; n += snprintf(fen+n, 4096 - n, "%s", pt.piece_abbreviation[piece][side]); } } } if (empty) n += snprintf(fen+n, 4096 - n, "-"); n += snprintf(fen+n, 4096 - n, "]"); } n += snprintf(fen+n, 4096 - n, " "); /* Second record: side to move */ if (board.side_to_move == WHITE) n += snprintf(fen+n, 4096 - n, "w "); else n += snprintf(fen+n, 4096 - n, "b "); /* Third record: castling rights * TODO: FRC-style strings. */ bool have_castle = false; for (int n = 0; n short_mask, long_mask; bool wrote_castle = false; for (side_t side = WHITE; side <= BLACK; side++) { short_mask = movegen.castle_mask[SHORT][side]; long_mask = movegen.castle_mask[LONG][side]; if (!short_mask.is_empty() && (short_mask & board.init) == short_mask) { char cc = 'k'; if (side == WHITE) cc = toupper(cc); n += snprintf(fen+n, 4096 - n, "%c", cc); wrote_castle = true; } if (!long_mask.is_empty() && (long_mask & board.init) == long_mask) { char cc = 'q'; if (side == WHITE) cc = toupper(cc); n += snprintf(fen+n, 4096 - n, "%c", cc); wrote_castle = true; } } if (!wrote_castle) n += snprintf(fen+n, 4096 - n, "-"); n += snprintf(fen+n, 4096 - n, " "); } /* Fourth record: en-passant square */ bool have_ep = false; for (int n = 0; n. */ #ifndef GAME_H #define GAME_H #include #include #include #include "xstring.h" #include "genrand.h" #include "bitboard.h" #include "pieces.h" #include "movegen.h" #include "move.h" #include "score.h" #include "hashtable.h" #include "evalhash.h" #include "eval_types.h" #include "eval_param.h" #include "timer.h" #include "pst.h" #include "san.h" #define MAX_SEARCH_DEPTH 60 /* maximum depth of search tree */ #define HARD_HORIZON -20 #define MAX_TOTAL_DEPTH (MAX_SEARCH_DEPTH - HARD_HORIZON) #define HASH_TABLE_SIZE (16*1024*1024) #undef USE_HISTORY_HEURISTIC static bool abort_search; enum play_state_t { SEARCH_OK=0, SEARCH_GAME_ENDED, SEARCH_GAME_ENDED_REPEAT, SEARCH_GAME_ENDED_50_MOVE, SEARCH_GAME_ENDED_MATE, SEARCH_GAME_ENDED_STALEMATE, SEARCH_GAME_ENDED_INSUFFICIENT, SEARCH_GAME_ENDED_LOSEBARE, SEARCH_GAME_ENDED_WINBARE, SEARCH_GAME_ENDED_FORFEIT, SEARCH_GAME_ENDED_INADEQUATEMATE, SEARCH_GAME_ENDED_FLAG_CAPTURED, SEARCH_GAME_ENDED_NOPIECES }; enum chase_state_t { NO_CHASE=0, DRAW_CHASE, LOSE_CHASE, WIN_CHASE }; /* Settings */ enum { MATE_SEARCH_DISABLED=0, MATE_SEARCH_ENABLE_DROP, MATE_SEARCH_ENABLED }; extern void (*default_iteration_output)(const char *, ...); extern void (*default_uci_output)(const char *, ...); extern void (*default_xboard_output)(const char *, ...); extern void (*default_error_output)(const char *, ...); extern size_t default_hash_size; struct game_t { /* Functions */ virtual ~game_t() {} virtual void setup_fen_position(const char * /* str */, bool skip_castle = false) { (void)skip_castle; } virtual const char *make_fen_string(char *buffer = NULL) const { return buffer; } virtual void start_new_game(void) {} virtual void set_transposition_table_size(size_t /* size */) {} virtual void print_board(FILE * file = stdout) const {(void)file;} virtual void print_bitboards() const {} virtual void generate_moves(movelist_t * /* movelist */) const {} virtual void generate_legal_moves(movelist_t * /* movelist */) const {} virtual void test_move_game_check() {} virtual side_t get_side_to_move() { return NUM_SIDES; } virtual bool player_in_check(side_t /* side*/ ) { return false; } virtual side_t side_piece_on_square(int /* square */) { return NONE; } virtual void playmove(move_t /* move*/) {} virtual void takeback() {} virtual int eval() { return 0; } virtual int static_qsearch(int /* beta */, int depth = 0) { (void)depth; return 0; } virtual int see(move_t /* move */) { return 0; } virtual size_t get_moves_played() { return 0 ; } virtual move_t move_string_to_move(const char * move_str, const movelist_t * external_movelist = NULL) const { (void)move_str,external_movelist; return 0; } virtual play_state_t think(int /* max_depth */) { return SEARCH_OK; } virtual bool ponder() { return false; } virtual bool analyse() { return false; } virtual void write_piece_descriptions(bool xb = false) const { (void)xb; } virtual void print_wiki_rules(void) {} virtual void print_rules(void) {} virtual void print_pieces(void) const {} virtual void print_attacker_bitboard(int /* square */) {} virtual void print_attack_bitboard(int /* square */) {} virtual int pack_rank_file(int /* rank */, int /* file */) { return 0; } virtual play_state_t get_game_end_state(movelist_t * movelist = NULL) { (void)movelist; return SEARCH_OK; } virtual void deduce_castle_flags(side_t /* side */, int /* king_from */, int /* king_to */, int /* rook_from */) {}; virtual void add_rule(uint32_t /* rule */) {} virtual void remove_rule(uint32_t /* rule */) {} virtual void set_maximum_number_of_pieces(const char * /* symbol */, side_t /* side */, int /* count */) {} virtual void set_maximum_number_of_kings(side_t /* side */, int /* count */) {} virtual chase_state_t test_chase() {return NO_CHASE;} virtual bool side_captured_flag(side_t /* side */) { return false; } const char *get_name() const { return name; } void set_default_output_function(void (*func)(const char *, ...)) { output_iteration = func; default_iteration_output = func; } void set_uci_output_function(void (*func)(const char *, ...)) { uci_output = func; default_uci_output = func; } void set_xboard_output_function(void (*func)(const char *, ...)) { xboard_output = func; default_xboard_output = func; } void set_error_output_function(void (*func)(const char *, ...)) { error_output = func; default_error_output = func; } move_t get_last_move() { if (moves_played) { return move_list[moves_played-1]; } return 0; } int files, ranks, holdsize; int virtual_files, virtual_ranks; /* Variables */ eval_t mate_score; /* The score returned for mate, normally -LEGALWIN */ eval_t stale_score; /* The score returned for stale mate, normally -LEGALDRAW */ eval_t rep_score; /* The score returned for a repetition, normally -LEGALDRAW */ eval_t bare_king_score; /* The score penalty for a lone king. Normally 0, but -LEGALWIN for shatranj */ eval_t no_piece_score; /* The score returned for having no pieces, normally -LEGALWIN */ eval_t flag_score; /* The score returned when flags are captured, normally -LEGALWIN */ eval_t perpetual; /* The score returned when an in-check position is repeated */ int repeat_claim; /* Make a claim if the root position has been repeated this many times */ eval_t resign_threshold; /* Increment resign count if the evaluation is below this limit */ eval_t draw_threshold; /* Increment draw count if the absolute evaluation is below this limit */ int resign_count; int draw_count; chess_clock_t clock; char *start_fen; /* FEN string encoding the starting position of this game */ char *xb_setup; /* setup string that has to be sent to XBoard (startup position will be attached) */ char *xb_parent; /* parent variant for XBoard */ int clock_nodes; int start_move_count; /* Full-move counter at the beginning of the game. */ size_t moves_played; /* Number of moves played to current position */ size_t last_move; /* Number of the last move played in the game; useful when we take back a move */ size_t max_moves; /* Maximum number of moves that can be stored */ move_t *move_list; /* list of moves played in the game */ int *move_clock; /* Time-control for engine clock */ uint64_t branches_pruned; movelist_t *movelist; /* Data structure for retrieving the principle variation. At each depth, * there are two branches for the tree: the principle variation and the * "current" branch. If the current branch turns out to be better than * the PV, it becomes the new PV. * A binary tree would be enough to store this information (and be easy * to manipulate), but for now we use a plain NxN array (of which half * the space is wasted, obviously) */ move_t principle_variation[MAX_TOTAL_DEPTH][MAX_TOTAL_DEPTH]; int length_of_variation[MAX_TOTAL_DEPTH]; move_t best_move[MAX_TOTAL_DEPTH]; /* Transposition table */ size_t hash_size; hash_table_t *transposition_table; /* Evaluation table */ eval_hash_table_t *eval_table; /* Hash table for repetition detection */ int8_t repetition_hash_table[0xFFFF+1]; int8_t board_repetition_hash_table[0xFFFF+1]; /* Whether the engine is currently pondering or not, if it is, disable * time control. */ bool pondering; move_t ponder_move; bool analysing; move_t analyse_move; movelist_t analyse_movelist; const char *analyse_fen; bool analyse_new; int analyse_undo; int analyse_moves_played; int option_ms; bool random_ok; bool trace; bool show_fail_high; bool show_fail_low; bool repetition_claim; int square_to_bit[256]; int bit_to_square[256]; int top_left; /* Various function pointers, so we can easily customise things and * adjust to different UIs. */ void (*output_iteration)(const char *, ...) ATTRIBUTE_FORMAT_PRINTF; void (*uci_output)(const char *, ...) ATTRIBUTE_FORMAT_PRINTF; void (*xboard_output)(const char *, ...) ATTRIBUTE_FORMAT_PRINTF; void (*error_output)(const char *, ...) ATTRIBUTE_FORMAT_PRINTF; bool (*check_keyboard)(struct game_t *game); /* Meta-data */ char *name; void truncate_principle_variation(int depth) { length_of_variation[depth] = depth; } inline void backup_principle_variation(int depth, move_t move) { /* Copy principle variation */ if (length_of_variation[depth+1] >= (depth+1)) { principle_variation[depth][depth] = move; for (int c=depth+1; c struct game_template_t : public game_t { board_t board; /* pointer to the current board position */ /* Rules */ piece_description_t pt; board_t root_board; /* The board position at the root of the search */ /* State information */ unmake_info_t *ui; movegen_t movegen; /* Killer moves, storage space requirements must come from the search * function. */ move_t killer[MAX_TOTAL_DEPTH][2]; move_t mate_killer[MAX_TOTAL_DEPTH]; /* Botwinnik-Markov extension. * This is like a killer move or a refutation move, but for NULL moves. * When encountering it on consecutive plies, extend the search (or at least sort the move higher in the * list). */ move_t null_killer[MAX_TOTAL_DEPTH]; /* Counter moves, for use with the counter move heuristic. * Indexed by from- and to square and side to move. */ move_t counter[8*sizeof(kind)][8*sizeof(kind)][NUM_SIDES]; /* Combination moves, similar to counter moves except indexed by our own * previous moves. * Indexed by from- and to square and side to move. */ move_t combo[8*sizeof(kind)][8*sizeof(kind)][2]; #if 0 /* History reductions, as discussed by Ed Schroeder. * The idea is to reduce the depth of moves that have failed low in the * past. This requires a history table. * This is indexed by colour, piece type and destination square. * NB: I tried colour/from square/destination square, and it seems to be * worse, at least with the parameters given by Ed Schroeder. Probably * because using the piece type means we can catch a bad move more * easily even if we moved the piece first (Rf5 exf5 is bad independent * of whether the rook was on f8 or f7, this situation catches both). */ int history_reduce[MAX_PIECE_TYPES][NUM_SIDES][8*sizeof(kind)]; #endif /* History heuristic */ int history[NUM_SIDES][MAX_PIECE_TYPES][8*sizeof(kind)]; int max_history[NUM_SIDES]; int drop_history[NUM_SIDES][MAX_PIECE_TYPES][8*sizeof(kind)]; int max_drop_history[NUM_SIDES]; void init() { movegen = movegen_t(); output_iteration = default_iteration_output; uci_output = default_uci_output; xboard_output = default_xboard_output; error_output = default_error_output; xb_setup = NULL; xb_parent = NULL; check_keyboard = NULL; max_moves = 0; move_list = NULL; move_clock = NULL; ui = NULL; board.flag[WHITE].clear(); board.flag[BLACK].clear(); transposition_table = NULL; eval_table = NULL; hash_size = default_hash_size; board.clear(); memset(&pt, 0, sizeof(pt)); board.piece_types = &pt; trace = false; show_fail_high = false; show_fail_low = false; repetition_claim = true; random_ok = false; analysing = false; pondering = false; analyse_fen = NULL; analyse_new = false; analyse_undo = 0; option_ms = MATE_SEARCH_ENABLE_DROP; movelist = new movelist_t[MAX_TOTAL_DEPTH+2]; keep_labels = false; for (int n=0; n<256; n++) { square_to_bit[n] = n; bit_to_square[n] = n; } for (int n=0; n() { init(); } game_template_t(int files, int ranks) { assert(files*ranks <= 8*sizeof(kind)); init(); set_board_size(files, ranks); } ~game_template_t() { free(move_list); free(move_clock); free(ui); delete[] movelist; destroy_hash_table(transposition_table); destroy_eval_hash_table(eval_table); } void assess_piece_mate_potential( bitboard_t reach_from[MAX_PIECE_TYPES][8*sizeof(kind)], bitboard_t attack_from[MAX_PIECE_TYPES][8*sizeof(kind)], bitboard_t attack_to[MAX_PIECE_TYPES][8*sizeof(kind)] ) { int king[NUM_SIDES] = { -1, -1 }; for (side_t side = WHITE; side <= BLACK; side++) { if (!(board.bbc[side] & board.royal).is_empty()) { king[side] = board.get_piece((board.bbc[side] & board.royal).bitscan()); continue; } assert(king[side] == -1); for (int n = 0; n dkzone = bitboard_t::board_all & bitboard_t::board_north & bitboard_t::board_westward[files/2]; int num_dks = dkzone.popcount(); #if defined _MSC_VER std::vector dks_list(num_dks); #else int dks_list[num_dks]; #endif int dki = 0; while (!dkzone.is_empty()) { bitboard_t mask = bitboard_t::board_all; if (!(dkzone & bitboard_t::board_east_edge).is_empty()) mask &= bitboard_t::board_east_edge; if (!(dkzone & mask & bitboard_t::board_north_edge).is_empty()) mask &= bitboard_t::board_north_edge; int sq = (mask & dkzone).bitscan(); dkzone.reset(sq); dks_list[dki++] = sq; } /* Mate potential for single pieces: detect if a mate position * exists */ for (int n=0; n dk, ak, dkm, akm; dk.set(dks); ak.set(aks); dkm = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[king[BLACK]], dks, (dk|ak), BLACK); akm = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[king[WHITE]], aks, (dk|ak), WHITE); dkm &= ~dk; /* Kings should not attack eachother. * The attacking king should not block all escape squares (making the position unreachable). * The kings should at least influence eachother, however. */ if ( !((ak|akm) & dk).is_empty() ) continue; if ( !((dk|dkm) & ak).is_empty() ) continue; if ( ((ak|akm) & dkm) == dkm ) continue; if ((attack_to[king[WHITE]][aks] & (dkm|dk)).is_empty()) continue; for (int ps = 0; ps < files*ranks; ps++) { if ( (ak|dk).test(ps) ) continue; if ((attack_to[n][ps] & (dkm|dk)).is_empty()) continue; bitboard_t p, pm; p.set(ps); pm = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[n], ps, (ak|p), WHITE); if ( ((pm | akm) & (dkm|dk)) == (dkm|dk) ) { pt.piece_flags[n] &= ~PF_CANTMATE; break; } } } } } /* Mate potential for pairs of pieces. * This is slightly more complicated because we need to do some * retrograde analysis to test whether the mate can be forced at * all. * TODO: only consider piece placement where it makes sense: * defending king near a corner, and attacking king where it takes * away some escape squares. Similarly, the other pieces should at * least attack some of the escape squares. */ for (int n1=0; n1 dk, ak, dkm, akm; dk.set(dks); ak.set(aks); dkm = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[king[BLACK]], dks, (dk|ak), BLACK); akm = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[king[WHITE]], aks, (dk|ak), WHITE); dkm &= ~dk; /* Kings should not attack eachother. * The attacking king should not block all escape squares (making the position unreachable). * The kings should at least influence eachother, however. */ if ( !((ak|akm) & dk).is_empty() ) continue; if ( !((dk|dkm) & ak).is_empty() ) continue; if ( ((ak|akm) & dkm) == dkm ) continue; if ((attack_to[king[WHITE]][aks] & (dkm|dk)).is_empty()) continue; /* Second and third piece */ int nn[2] = {n1, n2}; int ps[2]; for (ps[0] = 0; ps[0] < files*ranks; ps[0]++) { if ( (ak|dk).test(ps[0]) ) continue; bitboard_t p[2]; p[0].set(ps[0]); if ((attack_to[nn[0]][ps[0]] & (dkm|dk)).is_empty()) continue; for (ps[1] = 0; ps[1] < files*ranks; ps[1]++) { if ( (ak|dk|p[0]).test(ps[1]) ) continue; p[1].clear(); p[1].set(ps[1]); if ((attack_to[nn[1]][ps[1]] & (dkm|dk)).is_empty()) continue; bitboard_t pa[2]; pa[0] = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[nn[0]], ps[0], (ak|p[0]|p[1]), WHITE); pa[1] = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[nn[1]], ps[1], (ak|p[0]|p[1]), WHITE); /* Is this mate? If not, skip. */ bitboard_t full_attack = akm | pa[0] | pa[1]; if ((full_attack & (dkm|dk)) != (dkm|dk)) continue; /* Identify checking piece; skip double-check. */ int c = 0; if (!(pa[1] & dk).is_empty()) c = 1; if (!(pa[0] & dk).is_empty() && c == 1) continue; /* Find all squares the defending king could * have come from, prior to stepping into the * corner. */ bitboard_t pk = dkm & ~(akm | ak | p[1-c]); /* Now find all alternative escape squares */ bitboard_t bb = pk; while(!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); bitboard_t escape = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[king[BLACK]], square, (dk|ak), BLACK); escape &= ~(ak | akm | pa[1-c]); /* Now find all places the checking piece could * have come from. */ bitboard_t sentry = reach_from[nn[c]][ps[c]] & ~(ak | dk | p[1-c]) & ~attack_from[nn[c]][dks]; if (escape == dk) { bitboard_t alt_escape = pk; alt_escape.reset(square); bitboard_t sp = sentry; bool exit = false; while (!sp.is_empty()) { int s1 = sp.bitscan(); sp.reset(s1); bitboard_t mask = alt_escape | p[c]; mask &= ~attack_from[nn[c]][s1]; if (mask.is_empty()) { pt.pieces_can_win[n1][n2] = pt.pieces_can_win[n2][n1] = true; exit = true; break; } } /* Alternative that distinguishes KFFK and * KBBK: if the alternate piece can cover * both its present location and the * alternate escape, that would also work. */ sp = p[1-c] | alt_escape; for (int s2 = 0; s2 board; board.piece_types = &pt; board.put_piece(king[BLACK], BLACK, dks); board.put_piece(king[WHITE], WHITE, aks); board.put_piece(nn[0], WHITE, ps[0]); board.put_piece(nn[1], WHITE, ps[1]); board.print(); pa[0].print(); printf("\n"); pa[1].print(); printf("\n"); dk.print(); } #endif /* If this set is not empty, then we could have delivered mate */ if (!sentry.is_empty()) pt.pieces_can_win[n1][n2] = pt.pieces_can_win[n2][n1] = true; } } } } } } } } } void initialise_tropism_tables() { bitboard_t occ; memset(pt.tropism, 127, sizeof pt.tropism); for (int piece = 0; piece kn; kn.set(s1); int n = 0; while (kn != bitboard_t::board_all && n < 32) { bitboard_t bb = kn; while (!bb.is_empty()) { int s2 = bb.bitscan(); bb.reset(s2); kn |= movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[piece], s2, occ, WHITE); if (n < pt.tropism[piece][s1][s2]) pt.tropism[piece][s1][s2] = n; } n++; } for (int s2=0; s2 eval_t correctly. // Slightly cleaner (on this end) would be to just implement this // directly by making eval_t a class. static void scale_eval(eval_t &ev, double scl) { ev = eval_t(ev*scl); } /* Crude guestimates for piece values. * This is largely a matter of numerology, but it is better than nothing... * See http://www.chess.com/forum/view/chess960-chess-variants/mathematics-of-relative-chess-piece-value?quote_id=4383142 * for a discussion of the relative worth of forward and capture moves. */ void initialise_piece_values() { bool set = false; for (int n=0; n init; init.set(cs); bitboard_t occ; bitboard_t forward = bitboard_t::board_northward[ranks/2]; bitboard_t backward = bitboard_t::board_southward[ranks/2]; bitboard_t sideward = bitboard_t::board_eastward[files/2] | bitboard_t::board_westward[files/2]; bitboard_t move = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[n], cs, occ, WHITE); bitboard_t atk = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[n], cs, occ, WHITE); bitboard_t board33 = init; board33 |= (board33 << 1) | (board33 >> 1); board33 |= (board33 << files) | (board33 >> files); bitboard_t board55 = board33; board55 |= (board55 << 1) | (board55 >> 1); board55 |= (board55 << files) | (board55 >> files); /* Get evaluation weight. * Penalise short-range pieces for which the 3x3 and 5x5 attack sets coincide. * Penalise colour-bound pieces. */ int move_count5 = (move & board55).popcount(); int move_count3 = (move & board33).popcount(); int attack_count5 = (move & board55).popcount(); int attack_count3 = (move & board33).popcount(); int forward_move_count5 = (move & board55 & forward).popcount(); int forward_move_count3 = (move & board33 & forward).popcount(); int forward_attack_count5 = (move & board55 & forward).popcount(); int forward_attack_count3 = (move & board33 & forward).popcount(); int backward_move_count5 = (move & board55 & backward).popcount(); int backward_move_count3 = (move & board33 & backward).popcount(); int backward_attack_count5 = (move & board55 & backward).popcount(); int backward_attack_count3 = (move & board33 & backward).popcount(); int sideward_move_count5 = (move & board55 & sideward).popcount(); int sideward_move_count3 = (move & board33 & sideward).popcount(); int sideward_attack_count5 = (move & board55 & sideward).popcount(); int sideward_attack_count3 = (move & board33 & sideward).popcount(); if ( ((move|init)&bitboard_t::board_dark).is_empty() || ((move|init)&bitboard_t::board_light).is_empty() ) { move_count3 = 0; attack_count3 = 0; } /* Captures count for 2/3 of the piece value */ attack_count5 *= 2; attack_count3 *= 2; if (forward_move_count5 != backward_move_count5) { move_count5 += (2*forward_move_count5 + sideward_move_count5)/3; move_count3 += forward_move_count3; attack_count5 += (2*forward_attack_count5 + sideward_attack_count5)/3; attack_count3 += forward_attack_count3; } if (sideward_move_count5 == 0) move_count3 = 0; if (sideward_attack_count5 == 0) attack_count3 = 0; if (move_count3 == move_count5 && move_count5 != forward_move_count5 ) move_count3 = 0; if (attack_count3 == attack_count5 && attack_count5 != forward_attack_count5) attack_count3 = 0; /* Guestimate piece value, normalised such that a rook (with * attack rank 12) is ~500. * This gets the pawn value wrong, however, since that also * depends on the possibility of promotion. */ pt.piece_value[n] = ((attack_count5 + move_count5 + attack_count3 + move_count3) * 500) / (3*12); } if (!set) return; /* Add contribution from promotions */ for (int n=0; n%s (%d %d %d)\n", pt.piece_name[n], pt.piece_name[id], pt.piece_name[k],pt.piece_value[id], pt.piece_value[k], pt.piece_value[id] - pt.piece_value[k]); pt.piece_value[n] += 100*(pt.piece_value[id] - pt.piece_value[k])/pt.piece_value[id]; } else { pt.piece_value[n] += pt.piece_value[k] / 20; } } } /* Down-scale material if we're playing a drop variant */ if (board.rule_flags & RF_USE_CAPTURE) for (int n=0; n reach_from[MAX_PIECE_TYPES][8*sizeof(kind)]; bitboard_t attack_from[MAX_PIECE_TYPES][8*sizeof(kind)]; bitboard_t attack_to[MAX_PIECE_TYPES][8*sizeof(kind)]; bitboard_t moves[MAX_PIECE_TYPES][8*sizeof(kind)][NUM_SIDES]; int ranks = bitboard_t::board_ranks; int files = bitboard_t::board_files; pt.pawn_index[WHITE] = -1; pt.pawn_index[BLACK] = -1; pt.royal_pieces = 0; pt.defensive_pieces = 0; pt.pawn_pieces = 0; pt.minor_pieces = 0; pt.major_pieces = 0; pt.super_pieces = 0; pt.shak_pieces = 0; memset(reach_from, 0, sizeof reach_from); memset(attack_from, 0, sizeof attack_from); setup_fen_position(start_fen); /* Classify the opening position as "closed" (unbroken pawn chain) or * "open" (open files exist). * This affects whether centre play is an important concept for pawns * or not. */ for (int n=0; n init; init.set(cs); bitboard_t occ; bitboard_t move = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[n], cs, occ, WHITE); bitboard_t from = init; bitboard_t to = move; /* Test whether this piece is colour bound */ if ( ((from|to) & bitboard_t::board_dark).is_empty() || ((from|to) & bitboard_t::board_light).is_empty() ) { pt.piece_flags[n] |= PF_PAIRBONUS | PF_COLOURBOUND; pt.eval_pair_bonus[n].mg = eval_t(PAIR_BONUS_MG * pt.piece_value[n]); pt.eval_pair_bonus[n].eg = eval_t(PAIR_BONUS_EG * pt.piece_value[n]); } /* Test whether this piece can return to its starting square */ for (int k = 0; k < files; k++) { if ( !(pt.piece_flags[n] & PF_NORET) ) break; from = to; to.clear(); while (!from.is_empty() && (to & init).is_empty()) { int fs = from.bitscan(); from.reset(fs); to |= movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[n], fs, occ, WHITE); } if (!(to & init).is_empty()) pt.piece_flags[n] &= ~PF_NORET; } /* Hack: the above algorithm detects if the piece can return to * its origin for some of its moves, but not for all of its moves. * Thus, it fails to detect the irreversibility of forward pawn * pushes in Xiangqi. * We "fix" this by explicitly testing for this situation. The * correct fix is to try each move on the initial square, and only * mark the piece as reversible if ALL of them can return. */ if ( (move & bitboard_t::board_southward[ranks/2]).is_empty() ) pt.piece_flags[n] |= PF_NORET; /* Determine weight of this piece for king attacks */ pt.king_safety_weight[n] = 1; bitboard_t board33 = init; board33 |= (board33 << 1) | (board33 >> 1); board33 |= (board33 << files) | (board33 >> files); bitboard_t board55 = board33; board55 |= (board55 << 1) | (board55 >> 1); board55 |= (board55 << files) | (board55 >> files); /* Get evaluation weight. * Penalise short-range pieces for which the 3x3 and 5x5 attack sets coincide. * Penalise colour-bound pieces. */ int count5 = (move & board55).popcount(); int count3 = (move & board33).popcount(); if ( (pt.piece_flags[n] & PF_COLOURBOUND) && !(pt.piece_flags[n] & PF_NORET) ) count3 = 0; if (count3 == count5) pt.king_safety_weight[n] = count5; else pt.king_safety_weight[n] = count5 + count3; //printf("%10s %d %d\n", pt.piece_name[n], count3, count5); if ((pt.piece_flags[n] & PF_NORET) && (count3 == count5)) { if (!(board.bbc[WHITE] & board.bbp[n]).is_empty()) pt.pawn_index[WHITE] = n; if (!(board.bbc[BLACK] & board.bbp[n]).is_empty()) pt.pawn_index[BLACK] = n; } /* Weighting for game-phase */ pt.phase_weight[n] = pt.king_safety_weight[n]; if (pt.piece_flags[n] & PF_ROYAL) pt.phase_weight[n] = 0; if (pt.pawn_index[WHITE] == n ) pt.phase_weight[n] = 0; if (pt.pawn_index[BLACK] == n ) pt.phase_weight[n] = 0; /* Mark all squares that could be reached from this square for * reverse lookup. * Collect global information about mobility while we're at it. */ pt.max_moves[n] = 0; pt.avg_moves[n] = 0; pt.min_moves[n] = ranks*files; from = bitboard_t :: board_all; int mobility[8*sizeof(kind)] = { 0 }; while (!from.is_empty()) { int fs = from.bitscan(); from.reset(fs); moves[n][fs][WHITE] = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[n], fs, occ, WHITE); moves[n][fs][BLACK] = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[n], fs, occ, BLACK); moves[n][fs][WHITE] &= pt.prison[WHITE][n]; moves[n][fs][BLACK] &= pt.prison[BLACK][n]; move = moves[n][fs][WHITE]; int mc = move.popcount(); mobility[fs] = std::max(1, mc); pt.avg_moves[n] += mc; if (pt.max_moves[n] < mc) pt.max_moves[n] = mc; if (pt.min_moves[n] > mc) pt.min_moves[n] = mc; bitboard_t bb = move; while (!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); bitboard_t move = movegen.generate_move_bitboard_for_flags(pt.piece_move_flags[n], square, occ, WHITE); mobility[fs] += move.popcount()/2; } while (!move.is_empty()) { int ts = move.bitscan(); move.reset(ts); reach_from[n][ts].set(fs); } move = movegen.generate_move_bitboard_for_flags(pt.piece_capture_flags[n], fs, occ, WHITE); attack_to[n][fs] |= move; while (!move.is_empty()) { int ts = move.bitscan(); move.reset(ts); attack_from[n][ts].set(fs); } } pt.avg_moves[n] = (pt.avg_moves[n] + ranks*files/2) / (ranks*files); /* Centre the mobility table */ int avg = 0; for (int square=0; square= 0) scale_eval(pt.eval_value[pt.pawn_index[WHITE]].mg, PAWN_SCALE_MG); if (pt.pawn_index[BLACK] >= 0 && pt.pawn_index[BLACK] != pt.pawn_index[WHITE]) scale_eval(pt.eval_value[pt.pawn_index[BLACK]].mg, PAWN_SCALE_MG); /* Detect defensive pieces, which do not contribute to the game phase. */ for (int n =0; n::board_north).is_empty() ) pt.defensive_pieces |= (1 << n); if ( (pt.prison[BLACK][n] & bitboard_t::board_south).is_empty() ) pt.defensive_pieces |= (1 << n); if (pt.defensive_pieces & (1 << n)) { pt.piece_flags[n] |= PF_PAIRBONUS; pt.eval_pair_bonus[n].mg = eval_t(PAIR_BONUS_MG * pt.piece_value[n]); pt.eval_pair_bonus[n].eg = eval_t(PAIR_BONUS_EG * pt.piece_value[n]); pt.phase_weight[n] = 0; } } /* Make lame leapers increase in value as pieces are exchanged. * Conversely, hoppers become (much) less valuable in the end game. */ for (int n =0; n front_attack_span[NUM_SIDES][8*sizeof(kind)]; for (side_t side=WHITE; side moves; moves.set(square); front_attack_span[side][square] |= movegen.generate_move_bitboard_from_squares_for_flags(attack_flags, moves, bitboard_t::board_empty, side); int n = 0; while (!moves.is_empty() && n < ranks*files) { moves = movegen.generate_move_bitboard_from_squares_for_flags(move_flags, moves, bitboard_t::board_empty, side); moves &= ~((bitboard_t::board_eastward[unpack_file(square)] | bitboard_t::board_westward[unpack_file(square)]) & bitboard_t::board_rank[unpack_rank(square)] ); pt.front_span[side][square] |= moves; n++; } front_attack_span[side][square] |= movegen.generate_move_bitboard_from_squares_for_flags(attack_flags, pt.front_span[side][square], bitboard_t::board_empty, side); } } for (side_t side=WHITE; side block = pt.front_span[next_side[side]][ds] | front_attack_span[next_side[side]][ds]; block.set(ds); if ( !(block & pt.front_span[side][as]).is_empty() ) pt.passer_mask[side][as].set(ds); } } } /* Weak pawns: pawns that cannot be protected because they are * backward or isolated. * Pawns are weak if there are no friendly pawns in the registered * mask. */ bitboard_t back_attack_span[NUM_SIDES][8*sizeof(kind)]; memset(back_attack_span, 0, sizeof back_attack_span); for (side_t side=WHITE; side back_span[8*sizeof(kind)]; memset(back_span, 0, sizeof back_span); for (int as=0; as::board_empty, side); pt.weak_mask[side][as] = back_attack_span[side][as]; } //int square = pack_rank_file(ranks/2, files/2); //printf("%s\n", square_names[square]); //back_span[square].print("\n"); //back_attack_span[side][square].print("\n"); //if (side == BLACK) exit(0); } /* Determine mate potential for pieces */ assess_piece_mate_potential(reach_from, attack_from, attack_to); /* Piece classification, for evaluation purposes: * - Royal: a royal piece type * - Pawn: the most basic piece; can promote * - Minor: a piece that cannot deliver mate (knight/bishop class) * - Major: a piece that can deliver mate (rook class) * - Super: an extremely strong piece (queen or better) */ for (int n=0; n= 20) pt.super_pieces |= (1<%s is compatible\n", pt.piece_notation[n], pt.piece_notation[k]); } //if (pointless) printf("Deferral of promotion of %s is pointless\n", pt.piece_name[n]); if (!pointless) pt.deferral_allowed |= (1< draw * major+minor vs major -> draw * super vs minor or major -> won */ pt.pawn_pieces &= ~pt.royal_pieces; pt.defensive_pieces &= ~(pt.royal_pieces | pt.pawn_pieces); pt.minor_pieces &= ~pt.pawn_pieces; pt.minor_pieces |= pt.defensive_pieces; pt.major_pieces &= ~(pt.minor_pieces | pt.pawn_pieces); pt.super_pieces &= ~(pt.major_pieces | pt.minor_pieces | pt.pawn_pieces); /* If we're not using a "shak" rule, set all pieces as able to give * "shak" (all checks are good for winning). */ if (!(board.rule_flags & RF_USE_SHAKMATE)) pt.shak_pieces = ~0; /* Classify the opening position as "closed" (unbroken pawn chain) or * "open" (open files exist). * This affects whether centre play is an important concept for pawns * or not. */ bitboard_t pawns; for (int n=0; n 0) pt.eval_pst[n][square].mg -= rank; if (board.rule_flags & RF_USE_CAPTURE) pt.eval_pst[n][square].mg += x; } } else { for (int square=0; square::board_north).test(square) ) { pt.eval_pst[n][square].mg += 2*pt.piece_value[n]/3; pt.eval_pst[n][square].eg += pt.piece_value[n]; } } } } /* Palace tropism */ for (int royal = 0; royal < pt.num_piece_types; royal++) { if ( !(pt.piece_flags[royal] & PF_ROYAL) ) continue; if ( pt.prison[WHITE][royal] == bitboard_t::board_all) continue; if ( pt.prison[BLACK][royal] == bitboard_t::board_all) continue; int piece = n; if (pt.royal_pieces & (1 << piece)) continue; if (pt.defensive_pieces & (1 << piece)) continue; #if defined _MSC_VER std::vector tropism(files*ranks); #else int tropism[files*ranks]; #endif int max_trop = 0; int avg_trop = 0; bitboard_t palace = pt.prison[BLACK][royal] & bitboard_t::board_north; for (int square = 0; square < ranks*files; square++) { tropism[square] = 0; //if (palace.test(square)) continue; bitboard_t bb = palace; while(!bb.is_empty()) { int s2 = bb.bitscan(); bb.reset(s2); tropism[square] += pt.tropism[piece][square][s2]; } max_trop = std::max(max_trop, tropism[square]); avg_trop += tropism[square]; } avg_trop = (avg_trop + ranks*files/2) / (ranks*files); for (int square = 0; square < ranks*files; square++) tropism[square] = avg_trop - tropism[square]; if (pt.pawn_pieces & (1 << piece)) { for (int square=files*(ranks-1); square flags = board.flag[n]; #if defined _MSC_VER std::vector tropism(files*ranks, 0); #else int tropism[files*ranks]; memset(tropism, 0, sizeof tropism); #endif int max_trop = 0; int avg_trop = 0; while (!flags.is_empty()) { int fs = flags.bitscan(); flags.reset(fs); for (int square=0; square= 0) ? virtual_files : files; board.virtual_ranks = (virtual_ranks >= 0) ? virtual_ranks : ranks; for (int n=0; n<128; n++) board.bit_to_square[n] = -1; for (int n=0; n<256; n++) if (square_to_bit[n] >= 0 && square_to_bit[n] < 128) { bit_to_square[square_to_bit[n]] = n; board.bit_to_square[square_to_bit[n]] = n; } /* Make sure any gaps in the board are deleted from masks */ for (side_t side = WHITE; side<=BLACK; side++) for (int n=0; n::board_all; pt.optional_promotion_zone[side][n] &= bitboard_t::board_all; pt.special_zone[side][n] &= bitboard_t::board_all; pt.prison[side][n] &= bitboard_t::board_all; pt.drop_zone[side][n] &= bitboard_t::board_all; } /* Holding size. * Royal pieces and pieces that demote on capture never go into * holdings. */ holdsize = 0; if (board.rule_flags & RF_USE_HOLDINGS) { for (int n=0; n>= 1; } int pack_rank_file(int rank, int file) { return bitboard_t::pack_rank_file(rank, file); } void print_board(FILE *file = stdout) const { board.print(file); } void print_pieces(void) const { pt.print(); printf("Steppers: %d\n", movegen.number_of_steppers-1); printf("Leapers: %d\n", movegen.number_of_leapers); printf("ALeapers: %d\n", movegen.number_of_aleapers); } void print_bitboards() const { board.print_bitboards(); } void generate_moves(movelist_t *movelist) const { movegen.generate_moves(movelist, &board, board.side_to_move); } void print_attacker_bitboard(int square) { movegen.get_all_attackers(&board, bitboard_t::board_all, square).print(); } void print_attack_bitboard(int square) { bitboard_t test_squares; bitboard_t source_mask; source_mask.set(square); movegen.generate_attack_bitboard(&board, test_squares, source_mask, board.get_side(square)).print(); } void test_move_game_check() { board.check(movegen.player_in_check(&board, board.side_to_move)); } void generate_legal_moves(movelist_t *movelist) const { movegen.generate_moves(movelist, &board, board.side_to_move); board_t board_copy = board; /* Now filter out the illegal moves */ int n = 0; side_t me = board.side_to_move; while(nnum_moves) { unmake_info_t ui; move_t move = movelist->move[n]; board_copy.makemove(move, &ui); bool illegal = movegen.player_in_check(&board_copy, me); board_copy.unmakemove(move, &ui); if (illegal) { movelist->num_moves--; movelist->move[n] = movelist->move[movelist->num_moves]; } else { n++; } } } #include "piece_rules.h" #include "board_rules.h" #include "fen.h" void start_new_game(void) { board.clear(); if (max_moves < 1000) max_moves = 1000; start_move_count = 0; moves_played = last_move = 0; random_ok = false; move_list = (move_t *)realloc(move_list, max_moves * sizeof *move_list); move_clock = (int *)realloc(move_clock, max_moves * sizeof *move_clock); ui = (unmake_info_t *)realloc(ui, max_moves * sizeof *ui); setup_fen_position(start_fen); memset(see_cache, 0, sizeof(see_cache)); destroy_hash_table(transposition_table); destroy_eval_hash_table(eval_table); transposition_table = create_hash_table(hash_size); eval_table = create_eval_hash_table(hash_size / 16); } void set_transposition_table_size(size_t size) { hash_size = default_hash_size = size; destroy_hash_table(transposition_table); destroy_eval_hash_table(eval_table); transposition_table = create_hash_table(hash_size); eval_table = create_eval_hash_table(hash_size / 16); } size_t get_moves_played() { return moves_played; } bool player_in_check(side_t side) { return movegen.player_in_check(&board, side); } side_t side_piece_on_square(int square) { if (board.bbc[WHITE].test(square)) return WHITE; if (board.bbc[BLACK].test(square)) return BLACK; return NONE; } side_t get_side_to_move() { return board.side_to_move; } void playmove(move_t move) { board.makemove(move, ui + moves_played); move_list[moves_played] = move; repetition_hash_table[board.hash&0xFFFF]++; if (board.rule_flags & RF_USE_CAPTURE) board_repetition_hash_table[board.board_hash&0xFFFF]++; for (int c = SHORT; c mask = movegen.castle_mask[c][next_side[board.side_to_move]]; if ((board.init & mask) != (ui[moves_played-1].init & mask)) { board.hash ^= flag_key[next_side[board.side_to_move]][c]; board.board_hash ^= flag_key[next_side[board.side_to_move]][c]; } } moves_played++; } void replaymove() { playmove(move_list[moves_played]); } void takeback() { if (moves_played) { moves_played--; repetition_hash_table[board.hash&0xFFFF]--; if (board.rule_flags & RF_USE_CAPTURE) board_repetition_hash_table[board.board_hash&0xFFFF]--; board.unmakemove(move_list[moves_played], ui + moves_played); } } #include "see.h" #include "killer.h" #include "history.h" #include "search.h" #include "movestring.h" void calculate_pawn_structure(pawn_structure_t *ps); template eval_t static_evaluation(side_t side_to_move, int alpha = -LEGALWIN, int beta = LEGALWIN); int eval() { return static_evaluation(board.side_to_move); } #include "betza_string.h" static const char *describe_move_flags(move_flag_t flags) { const char *desc = "compound"; if ( (flags & ~MF_LEAPER_FLAGS) == 0) { desc = "leaper"; if (is_aleaper(flags)) desc = "asymmetric leaper"; if (is_double_leaper(flags)) desc = "double leaper"; if (is_masked_leaper(flags)) desc = "lame leaper"; } else if ( (flags & ~MF_SLIDER) == 0) { desc = "slider"; } else if ( (flags & ~MF_HOPPER) == 0) { desc = "hopper (it must leap over enemy pieces)"; } else if ( (flags & ~MF_STEPPER) == 0) { desc = "stepper"; } return desc; } void print_wiki_rules(void) { board_t backup_board = board; int8_t backup_repetition_hash_table[0xFFFF+1]; int8_t backup_board_repetition_hash_table[0xFFFF+1]; memcpy(backup_repetition_hash_table, repetition_hash_table, sizeof repetition_hash_table); memcpy(backup_board_repetition_hash_table, board_repetition_hash_table, sizeof board_repetition_hash_table); bool promotions = false; bool drops = false; setup_fen_position(start_fen); printf("{{AutomaticRules}}\n"); printf("
\n%s\nThe opening position for %s.
\n", start_fen, name); int ranks = (virtual_ranks > 0) ? virtual_ranks : this->ranks; int files = (virtual_files > 0) ? virtual_files : this->files; printf("=Rules=\n"); printf("\n"); printf("%s is played on a %dx%d board.
\n", name, files, ranks); printf("%s moves first.
\n", (board.side_to_move == WHITE) ? "White" : "Black"); for (int n=0; n 0) { printf("White begins the game with %d %s%s (%s)", nw, pt.piece_name[n], (nw == 1) ? "" : plural, pt.piece_abbreviation[n][WHITE]); if (nhw) printf(" and %d held in-hand", nhw); if (nb) printf("
\n"); } if (nb > 0) { printf("Black begins the game with %d %s%s (%s)", nb, pt.piece_name[n], (nb == 1) ? "" : plural, pt.piece_abbreviation[n][WHITE]); if (nhb) printf(" and %d held in-hand", nhb); } } printf("
\n"); } for (int n=0; n\n", pt.piece_name[n]); if (board.rule_flags & RF_KING_TRAPPED) printf("The %s may not leave the Palace.
\n", pt.piece_name[n]); if (board.rule_flags & RF_KING_TABOO) printf("The %ss may not face eachother along an open file.
\n", pt.piece_name[n]); if (board.rule_flags & RF_KING_DUPLECHECK) printf("If all %ss are under attack, at least one of them must be taken out of check.
\n", pt.piece_name[n]); } } if (board.rule_flags & RF_FORCE_CAPTURE) printf("Captures are compulsory.
\n"); if (board.rule_flags & RF_KEEP_CAPTURE) printf("Captured pieces go to your hand.
\n"); if (board.rule_flags & RF_RETURN_CAPTURE) printf("Captured pieces are returned to your opponent's hand.
\n"); if (board.rule_flags & RF_ALLOW_PICKUP) printf("Pieces may be taken in-hand as a move.
\n"); if (board.rule_flags & RF_ALLOW_DROPS) printf("Pieces in-hand %s be dropped on an empty square. This counts as a move.
\n", (board.rule_flags & RF_FORCE_DROPS) ? "must immediately" : "may"); if (board.rule_flags & RF_GATE_DROPS) printf("Pieces in-hand may be gated in when moving a back-rank piece.
\n"); printf("\n"); printf("==Objectives==\n"); printf("The game is won:\n"); if (mate_score < 0) printf("* If the enemy king is check-mated.\n"); if (stale_score < 0) printf("* If the enemy king is stale-mated.\n"); if (bare_king_score < 0) printf("* If the enemy only has a king left and cannot take your last piece\n"); if (rep_score == LEGALLOSS) printf("* If the same position occurs for the third time.\n"); if (no_piece_score < 0 && board.royal.is_empty()) printf("* If the enemy has no pieces left.\n"); if (flag_score < 0 && board.rule_flags & RF_CAPTURE_THE_FLAG) printf("* If the enemy flags have been captured.\n"); printf("\n"); printf("The game is a draw:\n"); if (mate_score == 0) printf("* If the enemy king is check-mated.\n"); if (stale_score == 0) printf("* If the enemy king is stale-mated.\n"); if (bare_king_score == 0) printf("* If the enemy only has a king left and cannot take your last piece\n"); if (no_piece_score == 0 && board.royal.is_empty()) printf("* If the enemy has no pieces left.\n"); if (flag_score == 0 && board.rule_flags & RF_CAPTURE_THE_FLAG) printf("* If the enemy flags have been captured.\n"); if (rep_score == 0) printf("* If the same position occurs for the third time.\n"); printf("* If no progress has been made for 50 consecutive moves.\n"); if (mate_score < 0) printf("* If there is insufficient material to mate the enemy king.\n"); printf("\n"); printf("==Movement of the pieces==\n"); printf("\n"); for (int n=0; n::pack_rank_file(ranks/2, files/2); const char lc = pt.piece_name[n][strlen(pt.piece_name[n])-1]; const char *plural = (lc == 's' || lc == 'z') ? "es" : "s"; printf("\n\n", pt.piece_name[n], pt.piece_abbreviation[n][WHITE]); const char *move_desc = describe_move_flags(pt.piece_move_flags[n]); const char *cap_desc = describe_move_flags(pt.piece_capture_flags[n]); printf("\n\n\n"); } printf("
[[%s]] (%s)
\n"); if (pt.piece_move_flags[n] == pt.piece_capture_flags[n] && pt.piece_move_flags[n]) { printf("The %s moves and captures as a %s (marked •).
\n", pt.piece_name[n], move_desc); } else { if (pt.piece_move_flags[n]) printf("The %s moves as a %s (marked •).
\n", pt.piece_name[n], move_desc); else printf("The %s cannot make non-capture moves.
\n", pt.piece_name[n]); if (pt.piece_capture_flags[n]) printf("The %s captures as a %s (marked ×).
\n", pt.piece_name[n], move_desc); else printf("The %s cannot make capture moves.
\n", pt.piece_name[n]); } printf("[[Betza description]]: %s
\n", piece_moves_to_betza(n));//move_flags_to_betza(pt.piece_move_flags[n])); if (pt.piece_flags[n] & PF_NORET) printf("The %s cannot move back to the square it came from.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_CASTLE) printf("The %s can castle.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_TAKE_EP) printf("The %s can capture en-passant.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_SHAK) printf("The %s delivers \"shak\" check.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_NOMATE) printf("The %s is not allowed to deliver mate.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_DROPNOCHECK) printf("The %s may not be dropped with check.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_DROPNOMATE) printf("The %s may not be dropped to deliver mate.
\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_DROPONEFILE) { if (pt.piece_drop_file_maximum[n] == 1) printf("The %s may not be dropped if there is already a friendly %s on the same file.
\n", pt.piece_name[n], pt.piece_name[n]); else printf("The %s may not be dropped if there are already %d friendly %s%s on the same file.
\n", pt.piece_name[n], pt.piece_drop_file_maximum[n], pt.piece_name[n], plural); } if (pt.piece_flags[n] & PF_DROPDEAD) printf("The %s may be dropped where it cannot move.
\n", pt.piece_name[n]); if (pt.piece_promotion_choice[n]) { printf("The %s can promote to a ", pt.piece_name[n]); promotions = true; bool first = true; piece_bit_t pc = pt.piece_promotion_choice[n]; while (pc) { int k = bitscan32(pc); pc ^= (1 << k); if (!first) { if (pc == 0) printf(" or "); else printf(", "); } printf("[[%s]]", pt.piece_name[k]); first = false; } printf(".
\n"); } if (pt.demotion[n] != n) printf("The %s demotes to %s when captured
\n", pt.piece_name[n], pt.piece_name[pt.demotion[n]]); char fen[4096] = { 0 }; int move_board[256]; memset(move_board, 0, sizeof(move_board)); bitboard_t xmark, omark; board_t demo = board; demo.clear(); demo.side_to_move = (nw > 0 || nb == 0) ? WHITE : BLACK; demo.put_piece(n, demo.side_to_move, centre_square); if (pt.piece_special_move_flags[n]) { int f = files/4; bitboard_t bb = pt.special_zone[demo.side_to_move][n] & bitboard_t::board_file[f]; f = 1; while (bb.is_empty() && f < files) { bb = pt.special_zone[demo.side_to_move][n] & bitboard_t::board_file[f]; f++; } if (!bb.is_empty()) { int s = bb.bitscan(); demo.put_piece(n, demo.side_to_move, s); move_board[bit_to_square[s]] = -1; } } omark = movegen.generate_moves_bitboard(&demo, bitboard_t::board_empty, demo.bbp[n], demo.side_to_move); xmark = movegen.generate_attack_bitboard(&demo, bitboard_t::board_empty, demo.bbp[n], demo.side_to_move); xmark &= ~omark; while (!xmark.is_empty()) { int s = xmark.bitscan(); xmark.reset(s); s = bit_to_square[s]; if (s < 0) continue; move_board[s] = 2; } while (!omark.is_empty()) { int s = omark.bitscan(); omark.reset(s); s = bit_to_square[s]; if (s < 0) continue; move_board[s] = 1; } for (int s = 0; s::board_all.test(bit)) move_board[s] = 3; } move_board[bit_to_square[centre_square]] = -1; int k = 0; for (int r = ranks-1; r>=0; r--) { int count = 0; for (int f = 0; f < files; f++) { int s = f + r * files; //printf("%+3d", move_board[s]); /* Empty? */ if (move_board[s] == 0) { count++; continue; } /* Not empty, do we have a count? */ if (count) k += snprintf(fen+k, 4096 - k, "%d", count); count = 0; if (move_board[s] == -1) { k += snprintf(fen+k, 4096-k, "%s", pt.piece_abbreviation[n][demo.side_to_move]); continue; } const char *colour_string = " .#*"; k += snprintf(fen+k, 4096-k, "%c", colour_string[move_board[s]]); } if (count) k += snprintf(fen+k, 4096 - k, "%d", count); if (r) k += snprintf(fen+k, 4096 - k, "/"); //printf("\n"); } //demo.print(stdout, xmark, omark); //printf("\n"); printf("
"); printf("%s", fen); printf("
\n\n"); if (promotions) { printf("==Promotion==\n"); printf("Promotions are allowed when a piece moves into %sthe promotion zone.
\n", (board.rule_flags & RF_PROMOTE_IN_PLACE) ? "" : "or out of "); if (board.rule_flags & RF_PROMOTE_IN_PLACE) printf("Pieces inside the promotion zone can also be promoted later. This counts as a move.
\n"); printf("\n"); for (int n=0; n 0 || nb == 0) ? WHITE : BLACK; printf("\n\n"); char fen[4096] = { 0 }; int move_board[256]; memset(move_board, 0, sizeof(move_board)); for (side_t side_to_move = (nw?WHITE:BLACK); side_to_move <= (nb?BLACK:WHITE); side_to_move++) { bitboard_t omark = pt.promotion_zone[side_to_move][n]; bitboard_t xmark = pt.optional_promotion_zone[side_to_move][n]; omark &= ~xmark; while (!xmark.is_empty()) { int s = xmark.bitscan(); xmark.reset(s); s = bit_to_square[s]; if (s < 0) continue; move_board[s] = 2 + 3*side_to_move; } while (!omark.is_empty()) { int s = omark.bitscan(); omark.reset(s); s = bit_to_square[s]; if (s < 0) continue; move_board[s] = 1 + 3*side_to_move; } for (int s = 0; s::board_all.test(bit)) move_board[s] = 3; } } int k = 0; for (int r = ranks-1; r>=0; r--) { int count = 0; for (int f = 0; f < files; f++) { int s = f + r * files; //printf("%+3d", move_board[s]); /* Empty? */ if (move_board[s] == 0) { count++; continue; } /* Not empty, do we have a count? */ if (count) k += snprintf(fen+k, 4096 - k, "%d", count); count = 0; const char *colour_string = " ,$*.#"; k += snprintf(fen+k, 4096-k, "%c", colour_string[move_board[s]]); } if (count) k += snprintf(fen+k, 4096 - k, "%d", count); if (r) k += snprintf(fen+k, 4096 - k, "/"); //printf("\n"); } //demo.print(stdout, xmark, omark); //printf("\n"); printf("\n\n", fen); } printf("
[[%s]] (%s)
\n", pt.piece_name[n], pt.piece_abbreviation[n][WHITE]); bitboard_t omark = pt.promotion_zone[side_to_move][n]; bitboard_t xmark = pt.optional_promotion_zone[side_to_move][n]; omark &= ~xmark; if (!omark.is_empty()) printf("The %s must promote when it reaches one of the squares marked with •.
\n", pt.piece_name[n]); if (!xmark.is_empty()) printf("The %s may promote when it reaches one of the squares marked with ×.
\n", pt.piece_name[n]); printf("The %s can promote to a ", pt.piece_name[n]); promotions = true; bool first = true; piece_bit_t pc = pt.piece_promotion_choice[n]; while (pc) { int k = bitscan32(pc); pc ^= (1 << k); if (!first) { if (pc == 0) printf(" or "); else printf(", "); } printf("[[%s]]", pt.piece_name[k]); first = false; } printf(".
\n"); if (pt.demotion[n] != n) printf("The %s demotes to %s when captured
\n", pt.piece_name[n], pt.piece_name[pt.demotion[n]]); printf("
%s
\n\n"); } printf("[[Category: %dx%d]]\n", files, ranks); if (board.rule_flags & RF_USE_DROPS) printf("[[Category: Games with drops]]\n"); board = backup_board; memcpy(repetition_hash_table, backup_repetition_hash_table, sizeof repetition_hash_table); memcpy(board_repetition_hash_table, backup_board_repetition_hash_table, sizeof board_repetition_hash_table); } void print_rules(void) { board_t backup_board = board; int8_t backup_repetition_hash_table[0xFFFF+1]; int8_t backup_board_repetition_hash_table[0xFFFF+1]; memcpy(backup_repetition_hash_table, repetition_hash_table, sizeof repetition_hash_table); memcpy(backup_board_repetition_hash_table, board_repetition_hash_table, sizeof board_repetition_hash_table); setup_fen_position(start_fen); int files = bitboard_t::board_files; int ranks = bitboard_t::board_ranks; printf("Rules of %s\n", name); printf("\n"); printf("%s is played on a %dx%d board\n", name, files, ranks); printf("%s moves first.\n", (board.side_to_move == WHITE) ? "White" : "Black"); printf("\n"); printf("The game is won:\n"); if (mate_score < 0) printf(" * If the enemy king is check-mated.\n"); if (stale_score < 0) printf(" * If the enemy king is stale-mated.\n"); if (bare_king_score < 0) printf(" * If the enemy only has a king left and cannot take your last piece\n"); if (rep_score == LEGALLOSS) printf(" * If the same position occurs for the third time.\n"); if (no_piece_score < 0 && board.royal.is_empty()) printf(" * If the enemy has no pieces left.\n"); if (flag_score < 0 && board.rule_flags & RF_CAPTURE_THE_FLAG) printf(" * If the enemy flags have been captured.\n"); printf("\n"); printf("The game is a draw:\n"); if (mate_score == 0) printf(" * If the enemy king is check-mated.\n"); if (stale_score == 0) printf(" * If the enemy king is stale-mated.\n"); if (bare_king_score == 0) printf(" * If the enemy only has a king left and cannot take your last piece\n"); if (no_piece_score == 0 && board.royal.is_empty()) printf(" * If the enemy has no pieces left.\n"); if (flag_score == 0 && board.rule_flags & RF_CAPTURE_THE_FLAG) printf(" * If the enemy flags have been captured.\n"); if (rep_score == 0) printf(" * If the same position occurs for the third time.\n"); printf(" * If no progress has been made for 50 consecutive moves.\n"); if (mate_score < 0) printf(" * If there is insufficient material to mate the enemy king.\n"); printf("\n"); printf("Movement of the pieces:\n"); for (int n=0; n::pack_rank_file(ranks/2, files/2); const char lc = pt.piece_name[n][strlen(pt.piece_name[n])-1]; const char *plural = (lc == 's' || lc == 'z') ? "es" : "s"; printf("The %s\n", pt.piece_name[n]); const char *move_desc = describe_move_flags(pt.piece_move_flags[n]); const char *cap_desc = describe_move_flags(pt.piece_capture_flags[n]); if (pt.piece_move_flags[n] == pt.piece_capture_flags[n] && pt.piece_move_flags[n]) { printf("The %s moves and captures as a %s (marked +).\n", pt.piece_name[n], move_desc); } else { if (pt.piece_move_flags[n]) printf("The %s moves as a %s (marked +).\n", pt.piece_name[n], move_desc); else printf("The %s cannot make non-capture moves.\n", pt.piece_name[n]); if (pt.piece_capture_flags[n]) printf("The %s captures as a %s (marked *).\n", pt.piece_name[n], move_desc); else printf("The %s cannot make capture moves.\n", pt.piece_name[n]); } printf("Betza description: %s\n", piece_moves_to_betza(n));//move_flags_to_betza(pt.piece_move_flags[n])); if (pt.piece_flags[n] & PF_NORET) printf("The %s cannot move back to the square it came from.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_CASTLE) printf("The %s can castle.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_TAKE_EP) printf("The %s can capture en-passant.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_SHAK) printf("The %s delivers \"shak\" check.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_NOMATE) printf("The %s is not allowed to deliver mate.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_DROPNOCHECK) printf("The %s may not be dropped with check.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_DROPNOMATE) printf("The %s may not be dropped to deliver mate.\n", pt.piece_name[n]); if (pt.piece_flags[n] & PF_DROPONEFILE) { if (pt.piece_drop_file_maximum[n] == 1) printf("The %s may not be dropped if there is already a friendly %s on the same file.\n", pt.piece_name[n], pt.piece_name[n]); else printf("The %s may not be dropped if there are already %d friendly %s%s on the same file.\n", pt.piece_name[n], pt.piece_drop_file_maximum[n], pt.piece_name[n], plural); } if (pt.piece_flags[n] & PF_COLOURBOUND) printf("The %s is colour bound.\n", pt.piece_name[n]); if (pt.defensive_pieces & (1 << n)) printf("The %s is a defensive piece.\n", pt.piece_name[n]); if (pt.pawn_pieces & (1 << n)) printf("The %s is a pawn-class piece.\n", pt.piece_name[n]); if (pt.minor_pieces & (1 << n)) printf("The %s is a minor piece.\n", pt.piece_name[n]); if (pt.major_pieces & (1 << n)) printf("The %s is a major piece.\n", pt.piece_name[n]); if (pt.super_pieces & (1 << n)) printf("The %s is a super piece.\n", pt.piece_name[n]); if (pt.pawn_index[WHITE] == n) printf("The %s is white's pawn-type piece\n", pt.piece_name[n]); if (pt.pawn_index[BLACK] == n) printf("The %s is black's pawn-type piece\n", pt.piece_name[n]); //printf("The %s has safety weight %d.\n", pt.piece_name[n], pt.king_safety_weight[n]); int nw = (board.bbp[n]&board.bbc[WHITE]).popcount(); int nb = (board.bbp[n]&board.bbc[BLACK]).popcount(); if (nw == nb) printf("White and black begin the game with %d %s%s\n", nw, pt.piece_name[n], (nw == 1) ? "" : (lc == 's' || lc == 'z') ? "es" : "s"); else { if (nw > 0) printf("White begins the game with %d %s%s\n", nw, pt.piece_name[n], (nw == 1) ? "" : (lc == 's' || lc == 'z') ? "es" : "s"); if (nb > 0) printf("Black begins the game with %d %s%s\n", nb, pt.piece_name[n], (nb == 1) ? "" : (lc == 's' || lc == 'z') ? "es" : "s"); } if (pt.piece_flags[n] & PF_ROYAL) printf("The %s is a royal piece (king).\n", pt.piece_name[n]); if (pt.piece_promotion_choice[n]) { printf("The %s can promote to a ", pt.piece_name[n]); bool first = true; piece_bit_t pc = pt.piece_promotion_choice[n]; while (pc) { int k = bitscan32(pc); pc ^= (1 << k); if (!first) { if (pc == 0) printf(" or "); else printf(", "); } printf("%s", pt.piece_name[k]); first = false; } printf(".\n"); bitboard_t pz[2], opz[2]; pz[WHITE] = pt.promotion_zone[WHITE][n]; pz[BLACK] = pt.promotion_zone[BLACK][n]; opz[WHITE] = pt.optional_promotion_zone[WHITE][n]; opz[BLACK] = pt.optional_promotion_zone[BLACK][n]; if (nw) { printf("A white %s promotes when it reaches ", pt.piece_name[n]); bool first = true; while(!pz[WHITE].is_empty()) { int square = pz[WHITE].bitscan(); pz[WHITE].reset(square); if (!first) { if (pz[WHITE].is_empty()) printf(" or "); else printf(", "); } first = false; printf("%s", square_names[square]); } printf(".\n"); if (!opz[WHITE].is_empty()) { printf("Promotion is optional on "); bool first = true; while(!opz[WHITE].is_empty()) { int square = opz[WHITE].bitscan(); opz[WHITE].reset(square); if (!first) { if (opz[WHITE].is_empty()) printf(" or "); else printf(", "); } first = false; printf("%s", square_names[square]); } printf(".\n"); } } if (nb) { printf("A black %s promotes when it reaches ", pt.piece_name[n]); bool first = true; while(!pz[BLACK].is_empty()) { int square = pz[BLACK].bitscan(); pz[BLACK].reset(square); if (!first) { if (pz[BLACK].is_empty()) printf(" or "); else printf(", "); } first = false; printf("%s", square_names[square]); } printf(".\n"); if (!opz[BLACK].is_empty()) { printf("Promotion is optional on "); bool first = true; while(!opz[BLACK].is_empty()) { int square = opz[BLACK].bitscan(); opz[BLACK].reset(square); if (!first) { if (opz[BLACK].is_empty()) printf(" or "); else printf(", "); } first = false; printf("%s", square_names[square]); } printf(".\n"); } } } if (pt.demotion[n] != n) printf("The %s demotes to %s when captured\n", pt.piece_name[n], pt.piece_name[pt.demotion[n]]); bitboard_t xmark, omark; board_t demo = board; demo.clear(); demo.side_to_move = (nw > 0 || nb == 0) ? WHITE : BLACK; demo.put_piece(n, demo.side_to_move, centre_square); if (pt.piece_special_move_flags[n]) { int f = files/4; bitboard_t bb = pt.special_zone[demo.side_to_move][n] & bitboard_t::board_file[f]; f = 1; while (bb.is_empty() && f < files) { bb = pt.special_zone[demo.side_to_move][n] & bitboard_t::board_file[f]; f++; } if (!bb.is_empty()) demo.put_piece(n, demo.side_to_move, bb.bitscan()); } xmark = movegen.generate_moves_bitboard(&demo, bitboard_t::board_empty, demo.bbp[n], demo.side_to_move); omark = movegen.generate_attack_bitboard(&demo, bitboard_t::board_empty, demo.bbp[n], demo.side_to_move); demo.print(stdout, xmark, omark); if (is_aleaper(pt.piece_move_flags[n]) || is_stepper(pt.piece_move_flags[n])) { demo.clear(); demo.side_to_move = next_side[demo.side_to_move]; demo.put_piece(n, demo.side_to_move, centre_square); if (pt.piece_special_move_flags[n]) { int f = files/4; bitboard_t bb = pt.special_zone[demo.side_to_move][n] & bitboard_t::board_file[f]; f = 1; while (bb.is_empty() && f < files) { bb = pt.special_zone[demo.side_to_move][n] & bitboard_t::board_file[f]; f++; } if (!bb.is_empty()) demo.put_piece(n, demo.side_to_move, bb.bitscan()); } xmark = movegen.generate_moves_bitboard(&demo, bitboard_t::board_empty, demo.bbp[n], demo.side_to_move); omark = movegen.generate_attack_bitboard(&demo, bitboard_t::board_empty, demo.bbp[n], demo.side_to_move); demo.print(stdout, xmark, omark); } printf("\n"); } board = backup_board; memcpy(repetition_hash_table, backup_repetition_hash_table, sizeof repetition_hash_table); memcpy(board_repetition_hash_table, backup_board_repetition_hash_table, sizeof board_repetition_hash_table); } void write_piece_descriptions(bool xb = false) const { if (xb) { for (int n=0; n. */ #include #include "pieces.h" #ifdef __cplusplus extern "C" { #endif extern uint64_t piece_key[MAX_PIECE_TYPES][2][128]; extern uint64_t hold_key[MAX_PIECE_TYPES][2][128]; extern uint64_t side_to_move_key; extern uint64_t flag_key[2][8]; extern uint64_t en_passant_key[128]; void initialise_hash_keys(void); #ifdef __cplusplus } #endif SjaakII/include/hashpath.h000644 000765 000024 00000001156 12433144250 016464 0ustar00eglebbkstaff000000 000000 #ifndef HASHPATH_H #define HASHPATH_H #include #include "move.h" #define MAX_HASH_PATH_LENGTH 128 typedef struct { uint64_t lock; move_t moves[MAX_HASH_PATH_LENGTH]; int length; int generation; } hash_path_entry_t; typedef struct { /* We keep two parallel hash tables: a "depth priority" table and an * "always replace" table. */ hash_path_table_entry_t *data; size_t number_of_elements; size_t write_count; uint8_t generation; } hash_path_table_t; hash_path_table_t *create_hash_path_table(size_t nelem); void destroy_hash_path_table(hash_path_table_t *table); #endif SjaakII/include/hashtable.h000644 000765 000024 00000004443 12433144250 016621 0ustar00eglebbkstaff000000 000000 /* Jazz, a program for playing chess * Copyright (C) 2009, 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef HASHTABLE_H #define HASHTABLE_H #include #include "move.h" /* Types of entries that may occur in the table (flags) */ #define HASH_TYPE_EXACT 0x00000001 #define HASH_TYPE_LOWER 0x00000002 #define HASH_TYPE_UPPER 0x00000004 #ifdef __cplusplus extern "C" { #endif /* Entries in the hash table */ typedef struct { uint32_t lock; /* Store the full key (for position verification) */ move_t best_move; /* The best move returned from the previous search */ int16_t score; /* The value of this node */ int16_t depth; /* The depth to which this position was searched; distance from horizon */ uint8_t flags; /* Properties of this entry */ uint8_t generation; /* Generation of this entry */ } hash_table_entry_t; typedef struct { /* We keep two parallel hash tables: a "depth priority" table and an * "always replace" table. */ hash_table_entry_t *data; size_t number_of_elements; size_t write_count; uint8_t generation; } hash_table_t; hash_table_t *create_hash_table(size_t nelem); void destroy_hash_table(hash_table_t *table); void store_table_entry(hash_table_t *table, uint64_t key, int depth, int score, unsigned int flags, move_t best_move); bool retrieve_table(hash_table_t *table, uint64_t key, int *depth, int *score, unsigned int *flags, move_t *best_move); void prefetch_hashtable(hash_table_t *table, uint64_t key); void prepare_hashtable_search(hash_table_t *table); int count_unused_table_entries(hash_table_t *table); #ifdef __cplusplus } #endif #endif SjaakII/include/history.h000644 000765 000024 00000006004 12502304433 016360 0ustar00eglebbkstaff000000 000000 #define HISTORY_MAX 0x4000 #define USE_HISTORY_HEURISTIC void update_drop_history(move_t move, int score) { #ifdef USE_HISTORY_HEURISTIC int history_score; int piece = get_move_piece(move); int side = board.side_to_move; int to = get_move_to(move); drop_history[side][piece][to] += score; history_score = abs(drop_history[side][piece][to]); if (history_score > max_drop_history[side]) max_drop_history[side] = history_score; /* Rescale as needed */ if (max_drop_history[side] > HISTORY_MAX) { max_drop_history[side] /= 2; for (side = 0; side <= 1; side++) for (piece=0; piece::board_ranks*bitboard_t::board_files; to++) drop_history[side][piece][to] /= 2; } #endif } void update_history(move_t move, int score) { #ifdef USE_HISTORY_HEURISTIC int history_score; if (board.check() || is_promotion_move(move) || is_capture_move(move) || is_pickup_move(move) || is_castle_move(move)) return; if (is_drop_move(move)) { update_drop_history(move, score); return; } int piece = get_move_piece(move); int side = board.side_to_move; int to = get_move_to(move); history[side][piece][to] += score; history_score = abs(history[side][piece][to]); if (history_score > max_history[side]) max_history[side] = history_score; /* Rescale as needed */ if (max_history[side] > HISTORY_MAX) { max_history[side] /= 2; for (side = 0; side <= 1; side++) for (piece=0; piece::board_ranks*bitboard_t::board_files; to++) history[side][piece][to] /= 2; } #endif } int get_move_history_score(const move_t move) const { #ifdef USE_HISTORY_HEURISTIC int piece = get_move_piece(move); int side = board.side_to_move; int to = get_move_to(move); if (is_drop_move(move)) return drop_history[side][piece][to]; else return history[side][piece][to]; #else return 0; #endif } int get_move_history_scale(move_t move) const { #ifdef USE_HISTORY_HEURISTIC int side = board.side_to_move; if (is_drop_move(move)) return max_drop_history[side]; else return max_history[side]; #else return 1; #endif } void clear_history() { #ifdef USE_HISTORY_HEURISTIC memset(history, 0, sizeof history); max_history[0] = max_history[1] = 0; memset(drop_history, 0, sizeof drop_history); max_drop_history[0] = max_drop_history[1] = 0; #endif } void scale_history() { #ifdef USE_HISTORY_HEURISTIC /* Scale down history scores */ for (int side = 0; side <= 1; side++) { max_history[side] /= 2; max_drop_history[side] /= 2; for (int piece=0; piece::board_ranks*bitboard_t::board_files; to++) { history[side][piece][to] /= 2; drop_history[side][piece][to] /= 2; } } #endif } SjaakII/include/keypressed.h000644 000765 000024 00000001700 12452210627 017040 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYPRESSED_H #define KEYPRESSED_H #ifdef __cplusplus extern "C" { #endif #include "bool.h" extern const bool ponder_ok; extern bool keyboard_input_waiting(void); #ifdef __cplusplus } #endif #endif SjaakII/include/killer.h000644 000765 000024 00000003563 12502304433 016150 0ustar00eglebbkstaff000000 000000 /* Store a "counter move"; this is a depth-independent extension of the * killer principle. */ void inline store_counter_move(int /* depth */, move_t prev_move, move_t move) { if (board.check() || is_promotion_move(move) || is_capture_move(move) || is_pickup_move(move) || !prev_move) return; int side = board.side_to_move; counter[get_move_from(prev_move)][get_move_to(prev_move)][side] = move; } bool inline is_counter(int /* depth */, move_t prev_move, move_t move) const { int side = board.side_to_move; return counter[get_move_from(prev_move)][get_move_to(prev_move)][side] == move; } bool is_killer(int depth, move_t move) const { if (killer[depth][0] == move || killer[depth][1] == move) return true; return false; } /* Store moves that kill a branch in the killer slots, but only if: * - we were not in check at the beginning of this move * - the move is not a promotion (already high in the tree) * - the move was not a capture (already high in the tree) */ inline void store_killer(move_t move, int depth) { if (board.check() || is_promotion_move(move) || is_capture_move(move)) return; if (move == killer[depth][0]) { /* The move was the first killer - do nothing */ } else { /* This was either the last killer (out of 2 or 3), or it's a new * move. Either way, Degrade first killer to second killer (etc) and * store the new first killer. */ killer[depth][1]=killer[depth][0]; killer[depth][0]=move; } } inline void store_mate_killer(move_t move, int depth, int best_score) { if (board.check() || is_promotion_move(move) || is_capture_move(move)) return; if (best_score >= (LEGALWIN-1000)) mate_killer[depth] = move; } void store_null_killer(int depth, move_t move) { if (!is_capture_move(move) && !is_promotion_move(move)) null_killer[depth] = move; } SjaakII/include/mate.h000644 000765 000024 00000016121 12473323312 015612 0ustar00eglebbkstaff000000 000000 //stage_t generate_staged_moves(stage_t stage, movelist_t *movelist, const board_t *board, side_t side_to_move) const // STAGE_DROP=STAGE_START, STAGE_NORMAL, /* Normal move generation */ // STAGE_CHECKING_DROP, STAGE_CHECKING_MOVE, /* Mate/Tsume search */ // STAGE_CHECK_EVADE, /* Check evasion */ // STAGE_DONE } stage_t; struct { uint32_t lock; int16_t score; int16_t ply; } mate_cache[0xFFFF + 1 + 8]; bool probe_mate_cache(int ply, int *score) { int index = board.hash & 0xFFFF; uint32_t key = board.hash >> 32; for (int n = 0; n<8; n++) { if (mate_cache[index + n].lock == key && mate_cache[index + n].ply <= ply) { *score = mate_cache[index + n].score; return true; } } return false; } void store_mate_cache(int ply, int score) { int index = board.hash & 0xFFFF; uint32_t key = board.hash >> 32; uint32_t okey = key; int oply = ply; int oscore = score; for (int n = 0; n<8; n++) { uint32_t new_key = mate_cache[index + n].lock; int new_ply = mate_cache[index + n].ply; int new_score = mate_cache[index + n].score; mate_cache[index+n].lock = okey; mate_cache[index+n].ply = oply; mate_cache[index+n].score = oscore; if (new_key == key) return; okey = new_key; oply = new_ply; oscore = new_score; } } /* Test if the current position is a +mate-in-mply-or-better, using * drop-checks. * Returns either a mate-score (if mate is found) or not. Matescores can be * trusted, non-mate scores indicate a call to reqular qsearch is in order. */ int msearch(int alpha, int beta, int mply, int depth, int ply = 0) { /* Check whether our search time for this move has expired */ check_clock(); if (abort_search) return 0; truncate_principle_variation(depth); move_t move = 0; int best_score = -ILLEGAL; if (ply == 0 && !(mply & 1)) mply--; if (mply < 0 || depth >= MAX_SEARCH_DEPTH) return 0; /* Test for transposition table cut-offs */ int hash_depth, hash_score; unsigned int hash_flag; move_t hash_move = 0; bool have_hash = retrieve_table(transposition_table, board.hash, &hash_depth, &hash_score, &hash_flag, &hash_move); have_hash = false; if (have_hash) { hash_score = score_from_hashtable(hash_score, depth); bool exact_ok = (depth > 0); if (is_mate_score(hash_score)) { if (hash_score > alpha) backup_principle_variation(depth, hash_move); return hash_score; } if (hash_depth >= mply) return 0; } if (probe_mate_cache(ply, &best_score)) { if (!is_mate_score(best_score)) return best_score; /* Follow the mating path, to reconstruct the like */ } best_score = -ILLEGAL; stage_t stage = STAGE_START; /* Generate moves */ if (ply & 1) { /* Evade */ assert(board.check()); stage = STAGE_CHECK_EVADE; } else { /* Begin with a drop */ if (board.check()) return 0; stage = STAGE_CHECKING_DROP; } move_t best = 0; side_t me = board.side_to_move; int legal_moves = 0; while (stage != STAGE_DONE && (alpha < beta)) { stage = movegen.generate_staged_moves(stage, movelist+depth, &board, me); legal_moves += movelist[depth].num_moves; for (int n = 0; n best_score) { best_score = score; hash_move = move; if (score > alpha && score) { hash_flag = HASH_TYPE_EXACT; best_move[depth] = move; backup_principle_variation(depth, move); alpha = score; if (ply == 0 && alpha >= LEGALWIN - 1000) alpha = beta; /* Cut-off if we found a mate - not necessarily the fastest one*/ if (alpha >= beta) { store_killer(move, depth); store_mate_killer(move, depth, score); hash_flag = HASH_TYPE_LOWER; break; } } } /* Take a cut-off: if we've reached the limit and found at least * one evasion, it's not mate. */ if (mply == 0) return 0; } /* Only consider check-drops in the first leg */ //if (ply == 0) break; } /* We only look for mates on odd plies */ if (legal_moves == 0 && (ply & 1)) { best_score = board.check() ? (mate_score + depth) : (stale_score + depth); move_t prev_move = move_list[moves_played-1]; /* Make sure mate wasn't caused by an illegal drop */ if (board.check() && is_drop_move(prev_move)) { int p = get_move_piece(prev_move); if (pt.piece_flags[p] & PF_DROPNOMATE) return ILLEGAL; } /* Test if the mate is legal, that is to say: * - The checking piece is allowed to deliver mate * - The mate follows a sequence of checks at least one of which * makes the mate OK (is classified as "shak"). * The first is illegal, the second is only a draw. */ if (board.check()) { if (!is_valid_mate()) return ILLEGAL; if (board.rule_flags & RF_USE_SHAKMATE) { if (!board.have_shak()) best_score = 0; } } } if (best_score == -ILLEGAL) best_score = 0; store_mate_cache(ply, best_score); if (is_mate_score(best_score)) /* Only mate scores are reliable */ store_table_entry(transposition_table, board.hash, mply, score_to_hashtable(best_score, depth), hash_flag, hash_move); return best_score; } SjaakII/include/move.h000644 000765 000024 00000036717 12502304433 015643 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOVE_H #define MOVE_H #include #include "assert.h" #include "pieces.h" #include "bool.h" /* Define structure to hold a move. * Because of the specific requirements of variants or other games, this has to be a fairly flexible data * structure. Each move can consist of (in that order): * N pickups (N = 0, 1, 2, 3) * N swaps (N = 0, 1, 2, 3) * N drops (N = 0, 1, 2, 3) * N store/retrieve (N = 0, 1) * A "pickup" stores a square (7 bits). * A "swap" stores the from - and to-square (7+7 = 14 bits). * A "drop" stores a square and a piece to be dropped there (7+5+1 = 13 bits). * A "store" stores a piece in the holdings (1+5+1 = 7 bits), a "retrieve" does the opposite * The extra bits ("4+1") for each piece are used to encode the colour of the piece. * * The order in which the components should be resolved is: * 1. pickups (so all destination squares are empty) * 2. swaps (which move pieces on the board) * 3. drops (which may happen on the square that was just cleared by the move) * 4. store/retrieve (could be any order really) * * Normal moves then consist of one swap (14 bits) * Captures consist of a pickup and a swap (7+14 = 21 bits) * Promotions consist of one (or two, for captures) pickup(s) and a drop (7(+7)+13 = 20(27) bits) * Castling consists of two swaps (14+14=28 bits) * Gating moves add an extra drop: * A castle+gate in this case takes up 28+13 = 41 bits (48 including retrieve) * A capture+gate takes 21+13 = 34 bits (41 including retrieve) * * For printing of SAN moves alone it is convenient to have the "primary" piece * type as well (4+1 bits). * bits * 0-1 Number of pickups (2 bits) * 2-3 Number of "swaps" (2 bits) * 4 Number of pieces taken/from holdings (0 or 1, 1 bit) * 5-6 Number of drops (2 bits) * 7-11 Primary piece (5 bits) * 12-59 Move actions (48 bits) * 60-63 Move flags (4 bits) * We even have room to expand the number of piece types to 32, which makes * implementing variants with many pieces easier (or possible at all). */ typedef uint64_t move_t; /* Offsets and test masks */ #define MOVE_SIDE_BITS 1 #define MOVE_PIECE_BITS (PIECE_BITS) #define MOVE_SQUARE_BITS 7 #define MOVE_PICKUP_SIZE (MOVE_SQUARE_BITS) #define MOVE_DROP_SIZE (MOVE_SQUARE_BITS + MOVE_PIECE_BITS + MOVE_SIDE_BITS) #define MOVE_SWAP_SIZE (MOVE_SQUARE_BITS + MOVE_SQUARE_BITS) #define MOVE_SQUARE_MASK ((1<> MOVE_PICK_SHIFT) & 0x03; } static inline int get_move_drops(move_t move) { return (move >> MOVE_DROP_SHIFT) & 0x03; } static inline int get_move_swaps(move_t move) { return (move >> MOVE_SWAP_SHIFT) & 0x03; } static inline int get_move_holdings(move_t move) { return (move >> MOVE_HOLD_SHIFT) & 0x01; } static inline move_t encode_number_pickups(int count) { assert(count <= 3); return count << MOVE_PICK_SHIFT; } static inline move_t encode_number_drops(int count) { assert(count <= 3); return count << MOVE_DROP_SHIFT; } static inline move_t encode_number_swaps(int count) { assert(count <= 3); return count << MOVE_SWAP_SHIFT; } static inline move_t encode_number_holdings(int count) { assert(count <= 1); return count << MOVE_HOLD_SHIFT; } static inline move_t encode_move_piece(int piece) { return (piece << MOVE_PIECE_SHIFT); } /* Get the first, second or third pickup */ static inline int get_move_pickup(move_t move, int n) { int shift; assert (n<=get_move_pickups(move)); shift = n * MOVE_PICKUP_SIZE; return (move >> (MOVE_SLOT1 + shift)) & MOVE_PICKUP_MASK; } /* Get the first, second or third drop */ static inline int get_move_drop(move_t move, int n) { int shift; assert (n<=get_move_drops(move)); shift = MOVE_DROP_SIZE*n + MOVE_SWAP_SIZE*get_move_swaps(move) + MOVE_PICKUP_SIZE*get_move_pickups(move); return (move >> (MOVE_SLOT1 + shift)) & MOVE_DROP_MASK; } static inline int get_move_swap(move_t move, int n) { int shift; assert (n<=get_move_swaps(move)); shift = MOVE_SWAP_SIZE*n + MOVE_PICKUP_SIZE*get_move_pickups(move); return (move >> (MOVE_SLOT1 + shift)) & MOVE_SWAP_MASK; } static inline int get_move_holding(move_t move) { int shift = MOVE_SWAP_SIZE*get_move_swaps(move) + MOVE_DROP_SIZE*get_move_drops(move) + MOVE_PICKUP_SIZE*get_move_pickups(move); return (move >> (MOVE_SLOT1 + shift)) & MOVE_HOLDING_MASK; } static inline int decode_swap_from(int swap) { return swap & MOVE_SQUARE_MASK; } static inline int decode_swap_to(int swap) { return (swap >> MOVE_SQUARE_BITS) & MOVE_SQUARE_MASK; } /* Decode drop and pickup piece/squares */ static inline int decode_drop_square(int drop) { return (drop >> DROP_SQUARE_SHIFT) & MOVE_SQUARE_MASK; } static inline int decode_drop_piece(int drop) { return drop & MOVE_PIECE_MASK; } static inline side_t decode_drop_side(int drop) { return side_for_piece(drop); } static inline int decode_pickup_square(int pickup) { return pickup; } /* The code for holdings is almost the same as for drops */ static inline int decode_holding_count(int hold) { return decode_drop_square(hold) - 2; } #define decode_holding_piece decode_drop_piece #define decode_holding_side decode_drop_side static inline uint64_t encode_swap(int from, int to) { return from | to << MOVE_SQUARE_BITS; } static inline uint64_t encode_pickup(int from) { return from & MOVE_SQUARE_MASK; } static inline uint64_t encode_drop(int piece, int to) { return piece | to< -2); assert((get_move_pickups(move) + get_move_drops(move)) < 5); count += 2; shift = MOVE_SLOT1 + MOVE_DROP_SIZE * get_move_drops(move) + MOVE_SWAP_SIZE * get_move_swaps(move) + MOVE_PICKUP_SIZE * get_move_pickups(move); return move | encode_number_holdings(1) | encode_holding(piece, count) << shift; } #define add_move_retrieve(move, piece, count) add_move_store((move), (piece), -(count)) /* Add gate information to a move: one extra drop, plus removing from * holdings. */ static inline move_t add_move_gate(move_t move, uint8_t piece, uint8_t to) { int drops = get_move_drops(move); int swaps = get_move_swaps(move); int pickups = get_move_pickups(move); int shift = MOVE_DROP_SIZE*drops + MOVE_SWAP_SIZE*get_move_swaps(move) + MOVE_PICKUP_SIZE*get_move_pickups(move); move &= ~encode_number_drops(3); move |= encode_number_drops(drops + 1) | encode_drop(piece, to) << (MOVE_SLOT1 + shift); move = add_move_retrieve(move, piece, 1); return move; } /* Query move types: * A normal move is one pickup, one drop (by the same piece) * A capture is two pickups (from two different sides), one drop * A promotion is a drop by a different piece type than a capture * A drop has no pickups * A "shot" is a pickup without a drop * Castling is two pickups and two drops */ static inline bool is_capture_move(move_t move) { return get_move_pickups(move) > get_move_drops(move); } static inline bool is_double_capture_move(move_t move) { return get_move_pickups(move) > get_move_drops(move)+1; } static inline bool is_promotion_move(move_t move) { unsigned int drop_piece; if (get_move_drops(move) != 1 || get_move_pickups(move) < 1) return false; drop_piece = decode_drop_piece(get_move_drop(move, 0)); return drop_piece != ((move >> MOVE_PIECE_SHIFT) & MOVE_PIECE_MASK); } static inline bool is_irreversible_move(move_t move) { return (move & MOVE_RESET50) != 0; } static inline bool is_drop_move(move_t move) { return (get_move_pickups(move) == 0) && (get_move_swaps(move) == 0) && (get_move_drops(move) == 1); } static inline bool is_pickup_move(move_t move) { return (get_move_pickups(move) == 1) && (get_move_swaps(move) == 0) && (get_move_drops(move) == 0); } static inline bool is_castle_move(move_t move) { return (get_move_swaps(move) == 2) || ((get_move_pickups(move) == 2) && (get_move_drops(move) == 2)); } static inline bool is_gate_move(move_t move) { return !is_drop_move(move) && (get_move_drops(move) > get_move_pickups(move)); } /* Convenience macros: the piece type of the first pickup and the first pickup and drop squares * By lucky coincidence, this works correctly for pure drop-moves too. */ static inline int get_move_piece(move_t move) { return (move >> MOVE_PIECE_SHIFT) & MOVE_PIECE_MASK; } static inline int get_move_promotion_piece(move_t move) { uint16_t p = get_move_drop(move, 0); return decode_drop_piece(p); } static inline int get_move_drop_square(move_t move) { uint16_t p; assert(is_drop_move(move) || is_gate_move(move)); p = get_move_drop(move, 0); return decode_drop_square(p); } static inline int get_move_from(move_t move) { uint16_t p; if (get_move_swaps(move)) { int swap = get_move_swap(move, 0); return decode_swap_from(swap); } p = get_move_pickup(move, 0); return decode_pickup_square(p); } static inline int get_move_to(move_t move) { uint16_t p; if (get_move_swaps(move)) { int swap = get_move_swap(move, 0); return decode_swap_to(swap); } p = get_move_drop(move, 0); return decode_drop_square(p); } static inline int get_castle_move_from2(move_t move) { uint16_t p; if (get_move_swaps(move) == 2) { int swap = get_move_swap(move, 1); return decode_swap_from(swap); } p = get_move_pickup(move, 1); return decode_pickup_square(p); } static inline int get_castle_move_to2(move_t move) { uint16_t p; if (get_move_swaps(move) == 2) { int swap = get_move_swap(move, 1); return decode_swap_to(swap); } p = get_move_drop(move, 1); return decode_drop_square(p); } static inline int get_move_capture_square(move_t move) { uint16_t p = 0; if (get_move_swaps(move)) p = get_move_pickup(move, 0); else p = get_move_pickup(move, 1); return decode_pickup_square(p); } #endif SjaakII/include/moveflag.h000644 000765 000024 00000006175 12452210627 016475 0ustar00eglebbkstaff000000 000000 #ifndef MOVEFLAG_H #define MOVEFLAG_H #include #include "assert.h" #include "bool.h" typedef uint32_t move_flag_t; #define MF_SLIDER_H 0x00000001 #define MF_SLIDER_V 0x00000002 #define MF_SLIDER_D 0x00000004 #define MF_SLIDER_A 0x00000008 #define MF_SLIDER 0x0000000F #define MF_HOPPER_H 0x00000010 #define MF_HOPPER_V 0x00000020 #define MF_HOPPER_D 0x00000040 #define MF_HOPPER_A 0x00000080 #define MF_HOPPER 0x000000F0 #define MF_HOPSLIDE (MF_HOPPER | MF_SLIDER) #define MF_STEPPER 0x00000F00 /* This is an index in an array with repeat counts */ #define MF_LEAPER 0x000F0000 /* This is an index in an array */ #define MF_LEAPER2 0x00F00000 /* Second index, for compound leapers */ #define MF_LEAPER_MASK 0x0F000000 /* Mask index, for compound leapers */ #define MF_IS_LEAPER 0x10000000 /* Whether this is actually a leaper */ #define MF_LEAPER_HAVE2 0x20000000 /* Leaper is a compound leaper */ #define MF_LEAPER_HAVEM 0x40000000 /* Leaper has a mask (only makes sense for compound leapers) */ #define MF_LEAPER_ASYMM 0x80000000 /* Leaper is asymmetric */ #define MF_LEAPER_FLAGS 0xFFFF0000 /* All leaper flags */ #define MF_HOPSLIDELEAP (MF_HOPSLIDE | MF_IS_LEAPER) /* Stepper repeat count masks (3 bits per direction) */ #define MF_STEPPER_N (0xf << 0) #define MF_STEPPER_NE (0xf << 4) #define MF_STEPPER_E (0xf << 8) #define MF_STEPPER_SE (0xf << 12) #define MF_STEPPER_S (0xf << 16) #define MF_STEPPER_SW (0xf << 20) #define MF_STEPPER_W (0xf << 24) #define MF_STEPPER_NW (0xf << 28) /* TODO: repeated leapers = riders, needs extension of the move_flag type. * Intended input file syntax: * Ride: (x,y) * (similar to asymmetric leaper) */ static inline bool is_slider(move_flag_t mf) { return (mf & MF_SLIDER) != 0; } static inline bool is_hopper(move_flag_t mf) { return (mf & MF_HOPPER) != 0; } static inline bool is_leaper(move_flag_t mf) { return (mf & MF_IS_LEAPER) != 0; } static inline bool is_aleaper(move_flag_t mf) { const move_flag_t flags = MF_LEAPER_ASYMM;// | MF_IS_LEAPER; return (mf & flags) == flags; } static inline bool is_simple_leaper(move_flag_t mf) { const move_flag_t flags = MF_LEAPER_HAVE2 | MF_LEAPER_HAVEM; return (mf & MF_IS_LEAPER) && !(mf & flags); } static inline bool is_double_leaper(move_flag_t mf) { const move_flag_t flags = MF_LEAPER_HAVE2;// | MF_IS_LEAPER; return (mf & flags) == flags; } static inline bool is_masked_leaper(move_flag_t mf) { const move_flag_t flags = MF_LEAPER_HAVEM;// | MF_IS_LEAPER; return (mf & flags) == flags; } static inline int get_leaper_index(move_flag_t mf) { return (mf & MF_LEAPER) >> 16; } static inline int get_leaper_index2(move_flag_t mf) { return (mf & MF_LEAPER2) >> 20; } static inline int get_leaper_indexm(move_flag_t mf) { return (mf & MF_LEAPER_MASK) >> 24; } static inline bool is_stepper(move_flag_t mf) { return (mf & MF_STEPPER) != 0; } static inline int get_stepper_index(move_flag_t mf) { return (mf & MF_STEPPER) >> 8; } static inline int make_stepper_index(int id) { assert(id < 16); return (id << 8); } #endif SjaakII/include/movegen.h000644 000765 000024 00000306014 12502304433 016323 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOVEGEN_H #define MOVEGEN_H #include #include #include "assert.h" #include "bitboard.h" #include "pieces.h" #include "board.h" #include "move.h" #include "movelist.h" #include "aligned_malloc.h" /* Stages for staged move generation */ typedef enum stage_t { STAGE_START=0, STAGE_DROP=STAGE_START, STAGE_NORMAL, /* Normal move generation */ STAGE_CHECKING_DROP, STAGE_CHECKING_MOVE, /* Mate/Tsume search */ STAGE_CHECK_EVADE, /* Check evasion */ STAGE_DONE } stage_t; static const stage_t next_stage[STAGE_DONE+1] = { // STAGE_DROP, STAGE_NORMAL, /* Normal move generation */ STAGE_NORMAL, STAGE_DONE, // STAGE_CHECKING_DROP, STAGE_CHECKING_MOVE, /* Mate/Tsume search */ STAGE_CHECKING_MOVE, STAGE_DONE, // STAGE_CHECK_EVADE, /* Check evasion */ STAGE_DONE, // STAGE_DONE STAGE_DONE }; inline stage_t& operator++(stage_t& stage, int) { assert(stage >= STAGE_START); assert(stage < STAGE_DONE); const int i = static_cast(stage)+1; stage = static_cast(i); return stage; } template struct movegen_t { /* Leapers and asymmetric leapers. */ bitboard_t leaper[MAX_LEAPER_TYPES][sizeof(kind)*8]; bitboard_t aleaper[NUM_SIDES][MAX_LEAPER_TYPES][sizeof(kind)*8]; int number_of_leapers; int number_of_aleapers; /* Stepper descriptions */ /* TODO: make stepper description and stepper_step depend on the * side-to-move, so we can re-use steppers for both sides, as for * asymmetric leapers. */ uint32_t stepper_description[MAX_STEPPER_TYPES][NUM_SIDES]; // 8 directions, with repeat counts (0-15) for each->32 bits bitboard_t stepper_step[MAX_STEPPER_TYPES][NUM_SIDES][sizeof(kind)*8]; bitboard_t step_mask[8]; int inverse_step[8]; int step_shift[8]; int number_of_steppers; /* Castling move bitboards */ bitboard_t castle_mask[NUM_CASTLE_MOVES][NUM_SIDES]; bitboard_t castle_free[NUM_CASTLE_MOVES][NUM_SIDES]; bitboard_t castle_safe[NUM_CASTLE_MOVES][NUM_SIDES]; int castle_king_from[NUM_CASTLE_MOVES][NUM_SIDES]; int castle_king_dest[NUM_CASTLE_MOVES][NUM_SIDES]; int castle_rook_dest[NUM_CASTLE_MOVES][NUM_SIDES]; /* Normal slider tables */ bitboard_t **horizontal_slider_move; bitboard_t **vertical_slider_move; bitboard_t **horizontal_hopper_move; bitboard_t **vertical_hopper_move; move_flag_t super_slider_flags; move_flag_t super_hopper_flags; /* Super piece */ bitboard_t super[sizeof(kind)*8]; bitboard_t super_slider[sizeof(kind)*8]; bitboard_t super_hopper[sizeof(kind)*8]; bitboard_t super_leaper[sizeof(kind)*8]; bitboard_t super_stepper[sizeof(kind)*8]; void initialise() { /* Clear leaper/stepper descriptions */ number_of_leapers = 0; number_of_aleapers = 0; number_of_steppers = 1; super_slider_flags = 0; super_hopper_flags = 0; memset(leaper, 0, sizeof leaper); memset(aleaper, 0, sizeof aleaper); memset(step_mask, 0, sizeof step_mask); memset(stepper_step, 0, sizeof stepper_step); for (int n = 0; n::board_files; // N step_shift[1] = bitboard_t::board_files+1; // NE step_shift[2] = 1; // E step_shift[3] =-bitboard_t::board_files+1; // SE step_shift[4] =-bitboard_t::board_files; // S step_shift[5] =-bitboard_t::board_files-1; // SW step_shift[6] =-1; // W step_shift[7] = bitboard_t::board_files-1; // NW /* N NE E SE S SW W NW * 0 1 2 3 4 5 6 7 * S SW W NW N NE E SE * 4 5 6 7 0 1 2 3 */ for (int n = 0; n<8; n++) inverse_step[n] = (n+4)&7; step_mask[0] = ~ bitboard_t::board_north_edge; step_mask[1] = ~(bitboard_t::board_east_edge | bitboard_t::board_north_edge); step_mask[2] = ~ bitboard_t::board_east_edge; step_mask[3] = ~(bitboard_t::board_east_edge | bitboard_t::board_south_edge); step_mask[4] = ~ bitboard_t::board_south_edge; step_mask[5] = ~(bitboard_t::board_west_edge | bitboard_t::board_south_edge);; step_mask[6] = ~ bitboard_t::board_west_edge; step_mask[7] = ~(bitboard_t::board_west_edge | bitboard_t::board_north_edge); for (int n = 0; n::board_files; int board_ranks = bitboard_t::board_ranks; int board_size = board_files * board_ranks; int file, rank; int occ; int n; /* Allocate memory for tables */ size_t file_table_size; size_t rank_table_size; size_t file_table_start; size_t rank_table_start; size_t file_table_offset; size_t rank_table_offset; uint8_t *memory; /* Determine size of tables: rank attacks, so index by file */ rank_table_size = board_files*sizeof(bitboard_t *); if (rank_table_size & 15) rank_table_size += 16 - (rank_table_size & 15); rank_table_start = rank_table_size; rank_table_size += board_files*(1<); rank_table_offset = ((size_t)1<); /* Determine size of tables: file attacks, so index by rank */ file_table_size = board_ranks*sizeof(bitboard_t *); if (file_table_size & 15) file_table_size += 16 - (file_table_size & 15); file_table_start = file_table_size; file_table_size += board_ranks*(1<); file_table_offset = ((size_t)1<); /* Free tables if previously allocated */ if (horizontal_slider_move) aligned_free(horizontal_slider_move); if (vertical_slider_move) aligned_free(vertical_slider_move ); if (horizontal_hopper_move) aligned_free(horizontal_hopper_move); if (vertical_hopper_move) aligned_free(vertical_hopper_move ); /* Allocate tables for horizontal (rank) attacks */ memory = (uint8_t *)aligned_malloc(rank_table_size, 16); assert(memory); memset(memory, 0, rank_table_size); horizontal_slider_move = (bitboard_t **)memory; for(n = 0; n *)(memory + rank_table_start + n*rank_table_offset); } memory = (uint8_t *)aligned_malloc(rank_table_size, 16); assert(memory); memset(memory, 0, rank_table_size); horizontal_hopper_move = (bitboard_t **)memory; for(n = 0; n *)(memory + rank_table_start + n*rank_table_offset); } /* Allocate tables for vertical (file) attacks */ memory = (uint8_t *)aligned_malloc(file_table_size, 16); assert(memory); memset(memory, 0, file_table_size); vertical_slider_move = (bitboard_t **)memory; for(n = 0; n *)(memory + file_table_start + n*file_table_offset); } memory = (uint8_t *)aligned_malloc(file_table_size, 16); assert(memory); memset(memory, 0, file_table_size); vertical_hopper_move = (bitboard_t **)memory; for(n = 0; n *)(memory + file_table_start + n*file_table_offset); } /* Rank attacks */ for (file = 0; file=0; n--) { horizontal_slider_move[file][occ] |= bitboard_t::board_file[n];//bitboard_t::square_bitboards[n]; if ( occ & (1 << n) ) break; } n--; /* Cannon attacks */ for (; n>=0; n--) { horizontal_hopper_move[file][occ] |= bitboard_t::board_file[n];//bitboard_t::square_bitboards[n]; if ( occ & (1 << n) ) break; } /* Right of slider position */ for (n=file+1; n::board_file[n];//bitboard_t::square_bitboards[n]; if ( occ & (1 << n) ) break; } n++; /* Cannon attacks */ for (; n::board_file[n];//bitboard_t::square_bitboards[n]; if ( occ & (1 << n) ) break; } } } /* File attacks */ for (rank = 0; rank < board_ranks; rank++) { for (occ = 0; occ < 1<=0; n--) { vertical_slider_move[rank][occ] |= bitboard_t::board_rank[n];//bitboard_t::square_bitboards[board_files*n]; if ( occ & (1 << n) ) break; } n--; /* Cannon attacks */ for (; n>=0; n--) { vertical_hopper_move[rank][occ] |= bitboard_t::board_rank[n];//bitboard_t::square_bitboards[board_files*n]; if ( occ & (1 << n) ) break; } /* North of slider position */ for (n=rank+1; n::board_rank[n];//bitboard_t::square_bitboards[board_files*n]; if ( occ & (1 << n) ) break; } n++; /* Cannon attacks */ for (; n::board_rank[n];//bitboard_t::square_bitboards[board_files*n]; if ( occ & (1 << n) ) break; } } } /* Initialise superpiece attacks to a full board */ for (n=0; n::board_all; } } void apply_board_masks(void) { int size = bitboard_t::board_files * bitboard_t::board_ranks; for (int n=0; n<8; n++) step_mask[n] &= bitboard_t::board_all; for (int n=0; n::board_all; } for (int n=0; n::board_all; aleaper[BLACK][n][s] &= bitboard_t::board_all; } } for (int n=0; n::board_all; stepper_step[n][BLACK][s] &= bitboard_t::board_all; } } } void initialise_super_tables(void) { int board_files = bitboard_t::board_files; int board_ranks = bitboard_t::board_ranks; int board_size = board_files * board_ranks; int n, c; /* Initialise stepper masks */ for (int c = 1; c stepper; stepper.set(n); stepper_step[c][WHITE][n] = generate_stepper_move_bitboard(make_stepper_index(c), WHITE, bitboard_t::board_empty, stepper); stepper_step[c][BLACK][n] = generate_stepper_move_bitboard(make_stepper_index(c), BLACK, bitboard_t::board_empty, stepper); } } for(n=0; n bb = stepper_step[c][side][n]; super_stepper[n] |= bb; while(!bb.is_empty()) { int s = bb.bitscan(); bb.reset(s); super_stepper[s].set(n); } } } } for(n=0; n::board_all; super_leaper[n].clear(); for (c=0; c::board_all; super_slider[n].clear(); super_slider[n] |= generate_slider_move_bitboard(super_slider_flags, WHITE, n, bitboard_t::board_empty); super_slider[n] &= bitboard_t::board_all; super_hopper[n].clear(); if (super_hopper_flags) super_hopper[n] |= generate_slider_move_bitboard(super_hopper_flags>>4, WHITE, n, bitboard_t::board_empty); super_hopper[n] &= bitboard_t::board_all; super[n] = super_hopper[n] | super_leaper[n] | super_slider[n] | super_stepper[n]; } } /* Move generator, per piece type */ bitboard_t generate_leaper_move_bitboard(move_flag_t flags, side_t side, int square, bitboard_t occ) const { assert(is_leaper(flags)); bitboard_t moves; int index = get_leaper_index(flags); moves = is_aleaper(flags) ? aleaper[side][index][square] : leaper [index][square]; /* Simple leaper? */ if (is_simple_leaper(flags)) return moves; /* Double-step leaper */ if (is_double_leaper(flags)) { bitboard_t bb = moves & ~occ; index = get_leaper_index2(flags); while (!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); moves |= leaper[index][square]; } } /* Masked leaper */ if (is_masked_leaper(flags)) { index = get_leaper_indexm(flags); moves &= leaper[index][square]; } return moves; } bitboard_t generate_slider_move_bitboard(move_flag_t flags, side_t /* side */, int square, bitboard_t occ) const { assert(is_slider(flags)); bitboard_t moves; int file = unpack_file(square); int rank = unpack_rank(square); int diag = occ.diagonal_nr[square]; int anti = occ.anti_diagonal_nr[square]; int index; if (flags & MF_SLIDER_H) { index = occ.get_rank(rank); moves |= horizontal_slider_move[file][index] & bitboard_t::board_rank[rank]; } if (flags & MF_SLIDER_V) { index = occ.get_file(file); moves |= vertical_slider_move[rank][index] & bitboard_t::board_file[file]; } if (flags & MF_SLIDER_D) { bitboard_t mask = bitboard_t::board_diagonal[diag]; index = (occ & mask).fill_south().get_rank(0); moves |= horizontal_slider_move[file][index] & mask; } if (flags & MF_SLIDER_A) { bitboard_t mask = bitboard_t::board_antidiagonal[anti]; index = (occ & mask).fill_south().get_rank(0); moves |= horizontal_slider_move[file][index] & mask; } return moves; } bitboard_t generate_hopper_move_bitboard(move_flag_t flags, side_t /* side */, int square, bitboard_t occ) const { assert(is_hopper(flags)); bitboard_t moves; int file = unpack_file(square); int rank = unpack_rank(square); int diag = occ.diagonal_nr[square]; int anti = occ.anti_diagonal_nr[square]; int index; //moves = generate_slider_move_bitboard(flags>>4, side, square, occ); //return generate_slider_move_bitboard(flags>>4, side, square, occ&~moves) ^ moves; if (flags & MF_HOPPER_H) { index = occ.get_rank(rank); moves |= horizontal_hopper_move[file][index] & bitboard_t::board_rank[rank]; } if (flags & MF_HOPPER_V) { index = occ.get_file(file); moves |= vertical_hopper_move[rank][index] & bitboard_t::board_file[file]; } if (flags & MF_HOPPER_D) { bitboard_t mask = bitboard_t::board_diagonal[diag]; index = (occ & mask).fill_south().get_rank(0); moves |= horizontal_hopper_move[file][index] & mask; } if (flags & MF_HOPPER_A) { bitboard_t mask = bitboard_t::board_antidiagonal[anti]; index = (occ & mask).fill_south().get_rank(0); moves |= horizontal_hopper_move[file][index] & mask; } return moves; } bitboard_t generate_stepper_move_bitboard(move_flag_t flags, side_t side, bitboard_t occ, bitboard_t steppers) const { bitboard_t moves; /* Check for single stepper moves, which are generated in parallel */ int si = get_stepper_index(flags); int d; for (d=0; d<8; d++) { int c = (stepper_description[si][side] >> (d*4)) & 15; bitboard_t dmoves = steppers; if (c == 0) continue; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for ( ; c>0; c--) { dmoves &= step_mask[d]; dmoves = dmoves.sshift(step_shift[d]); moves |= dmoves; dmoves &= ~occ; } } return moves; } bitboard_t generate_super_attacks_for_squares(bitboard_t squares, const bitboard_t super[sizeof(kind)*8]) const { bitboard_t attacks; while (!squares.is_empty()) { int square = squares.bitscan(); squares.reset(square); attacks |= super[square]; } return attacks; } /* Generate an attack bitboard for all attackers within a specified mask */ inline bitboard_t generate_attack_bitboard_mask(const board_t *board, const bitboard_t test_squares, const bitboard_t source_mask, const bitboard_t occ_mask, side_t side_to_move) const { piece_description_t *piece_types; move_flag_t *piece_capture_flags; bitboard_t own, enemy, own_movers; bitboard_t occupied; bitboard_t attacked; int n; piece_types = board->piece_types; piece_capture_flags = piece_types->piece_capture_flags; /* Bookkeeping: we keep a pointer to the next move in the move list, and * update the number of moves in the list at the end of this function */ own = board->bbc[side_to_move] & occ_mask; enemy = board->bbc[next_side[side_to_move]] & occ_mask; occupied = own | enemy | test_squares; own_movers = own & source_mask; bitboard_t possible_attackers = own_movers; for (n=0; nnum_piece_types && !possible_attackers.is_empty(); n++) { if ((possible_attackers & board->bbp[n]).is_empty()) continue; possible_attackers &= ~board->bbp[n]; bitboard_t bb = own_movers & board->bbp[n]; /* Steppers */ if (is_stepper(piece_capture_flags[n])) { int si = get_stepper_index(piece_capture_flags[n]); int d; for (d=0; d<8; d++) { int c = (stepper_description[si][side_to_move] >> (d*4)) & 15; bitboard_t captures = bb; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for ( ; c>0; c--) { captures &= step_mask[d]; captures = captures.sshift(step_shift[d]); captures &= piece_types->prison[side_to_move][n]; attacked |= captures; captures &= ~occupied; } } } /* Sliders and leapers */ if (piece_capture_flags[n] & MF_HOPSLIDELEAP) while (!bb.is_empty()) { move_flag_t capture_flags = piece_capture_flags[n]; int from = bb.bitscan(); bb.reset(from); if (is_leaper(capture_flags)) attacked |= generate_leaper_move_bitboard(capture_flags, side_to_move, from, occupied); if (is_slider(capture_flags)) attacked |= generate_slider_move_bitboard(capture_flags, side_to_move, from, occupied); if (is_hopper(capture_flags)) attacked |= generate_hopper_move_bitboard(capture_flags, side_to_move, from, occupied); attacked &= piece_types->prison[side_to_move][n]; } } return attacked; } inline bitboard_t generate_attack_bitboard(const board_t *board, const bitboard_t test_squares, const bitboard_t source_mask, side_t side_to_move) const { return generate_attack_bitboard_mask(board, test_squares, source_mask, bitboard_t::board_all, side_to_move); } inline bitboard_t generate_move_bitboard_for_flags(move_flag_t flags, int square, const bitboard_t occupied, side_t side_to_move) const { bitboard_t attacked; /* Steppers */ if (is_stepper(flags)) { bitboard_t bb = bitboard_t::square_bitboards[square]; int si = get_stepper_index(flags); for (int d=0; d<8; d++) { int c = (stepper_description[si][side_to_move] >> (d*4)) & 15; bitboard_t captures = bb; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for ( ; c>0; c--) { captures &= step_mask[d]; captures = captures.sshift(step_shift[d]); attacked |= captures; captures &= ~occupied; } } } /* Sliders and leapers */ if (flags & MF_HOPSLIDELEAP) { if (is_leaper(flags)) attacked |= generate_leaper_move_bitboard(flags, side_to_move, square, occupied); if (is_slider(flags)) attacked |= generate_slider_move_bitboard(flags, side_to_move, square, occupied); if (is_hopper(flags)) attacked |= generate_hopper_move_bitboard(flags, side_to_move, square, occupied); } return attacked; } inline bitboard_t generate_move_bitboard_from_squares_for_flags(move_flag_t flags, bitboard_t squares, const bitboard_t occupied, side_t side_to_move) const { bitboard_t attacked; while (!squares.is_empty()) { int square = squares.bitscan(); squares.reset(square); attacked |= generate_move_bitboard_for_flags(flags, square, occupied, side_to_move); } return attacked; } /* Generate an attack bitboard for all attackers within a specified mask */ inline bitboard_t generate_moves_bitboard(const board_t *board, bitboard_t test_squares, bitboard_t source_mask, side_t side_to_move) const { piece_description_t *piece_types; move_flag_t *piece_move_flags; bitboard_t own, enemy, own_movers; bitboard_t occupied; bitboard_t attacked; int n; piece_types = board->piece_types; /* Bookkeeping: we keep a pointer to the next move in the move list, and * update the number of moves in the list at the end of this function */ own = board->bbc[side_to_move]; enemy = board->bbc[next_side[side_to_move]]; occupied = own | enemy | test_squares; own_movers = own & source_mask; for (int k = 0; k<2; k++) { piece_move_flags = (k == 0) ? piece_types->piece_move_flags : piece_types->piece_special_move_flags; for (int n=0; nnum_piece_types; n++) { bitboard_t possible_attackers = own_movers & board->bbp[n]; if (piece_move_flags[n] == 0) continue; if (k == 1) possible_attackers &= piece_types->special_zone[side_to_move][n]; if (possible_attackers.is_empty()) continue; bitboard_t bb = possible_attackers; /* Steppers */ if (is_stepper(piece_move_flags[n])) { int si = get_stepper_index(piece_move_flags[n]); int d; for (d=0; d<8; d++) { int c = (stepper_description[si][side_to_move] >> (d*4)) & 15; bitboard_t captures = bb; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for ( ; c>0; c--) { captures &= step_mask[d]; captures = captures.sshift(step_shift[d]); captures &= piece_types->prison[side_to_move][n]; attacked |= captures; captures &= ~occupied; } } } /* Sliders and leapers */ if (piece_move_flags[n] & MF_HOPSLIDELEAP) while (!bb.is_empty()) { move_flag_t capture_flags = piece_move_flags[n]; int from = bb.bitscan(); bb.reset(from); if (is_leaper(capture_flags)) attacked |= generate_leaper_move_bitboard(capture_flags, side_to_move, from, occupied); if (is_slider(capture_flags)) attacked |= generate_slider_move_bitboard(capture_flags, side_to_move, from, occupied); if (is_hopper(capture_flags)) attacked |= generate_hopper_move_bitboard(capture_flags, side_to_move, from, occupied); } attacked &= piece_types->prison[side_to_move][n]; } } return attacked; } move_flag_t define_slider(const char *movestr) { const char *s = movestr; move_flag_t flags = 0; while (*s && isspace(*s)) s++; if (*s == '\0') return 0; int shift = 0; if (strstr(s, "slide") == s) shift = 0; if (strstr(s, "hop") == s) shift = 4; while (*s) { switch (*s) { case 'H': flags |= MF_SLIDER_H << shift; break; case 'V': flags |= MF_SLIDER_V << shift; break; case 'D': flags |= MF_SLIDER_D << shift; break; case 'A': flags |= MF_SLIDER_A << shift; break; case ')': break; default: break; } s++; } if (shift == 0) super_slider_flags |= flags; else super_hopper_flags |= flags; return flags; } move_flag_t define_asymmetric_leaper(const char *movestr) { int board_files = bitboard_t::board_files; int board_ranks = bitboard_t::board_ranks; int size = board_files * board_ranks; bitboard_t moves[3][NUM_SIDES][sizeof(kind)*8]; const char *s = movestr; char op = ' '; int ii, index_flags; ii = index_flags = 0; uint8_t description = 0; while (*s && *s != ' ') s++; s++; while (*s) { int n, m; while (*s && s[-1] != '(') s++; while (*s && *s == '(') s++; if(!*s) break; sscanf(s, "%d", &n); while (*s && s[-1] != ',') s++; if(!*s) break; sscanf(s, "%d", &m); s++; switch (op) { case '|': /* Define a leaper with more than one type of move */ case ' ': ii = 0; index_flags |= 1; break; case '+': /* A compound leaper, with two steps one after the other */ ii = 1; index_flags |= 2; printf("Error (Compound asymmetric leapers are not implemented)\n"); break; case '&': /* A compound leaper, with a mask (used to implement "lame leapers") */ /* Define a new type of leaper for the mask. * FIXME: check if this type was already defined and re-use. */ ii = 2; index_flags |= 4; printf("Error (lame asymmetric leapers are not implemented)\n"); break; } for (int sqr=0; sqr= MAX_LEAPER_TYPES) { printf("Error (too many aleapers)\n"); return 0; } for (int sqr = 0; sqr < size; sqr++) { aleaper[WHITE][number_of_aleapers][sqr] = moves[ii][WHITE][sqr]; aleaper[BLACK][number_of_aleapers][sqr] = moves[ii][BLACK][sqr]; } index[ii] = number_of_aleapers; number_of_aleapers++; } } return (index[0] | (index[1] << 4) | (index[2] << 8) | (index_flags << 12))<<16 | MF_LEAPER_ASYMM | MF_IS_LEAPER; } move_flag_t define_symmetric_leaper(const char *movestr) { int board_files = bitboard_t::board_files; int board_ranks = bitboard_t::board_ranks; int size = board_files * board_ranks; bitboard_t moves[3][sizeof(kind)*8]; const char *s = movestr; char op = ' '; int ii, index_flags; ii = index_flags = 0; uint8_t description = 0; while (*s && *s != ' ') s++; s++; while (*s) { int n, m; while (*s && s[-1] != '(') s++; while (*s && *s == '(') s++; if(!*s) break; sscanf(s, "%d", &n); while (*s && s[-1] != ',') s++; if(!*s) break; sscanf(s, "%d", &m); s++; switch (op) { case '|': /* Define a leaper with more than one type of move */ case ' ': ii = 0; index_flags |= 1; break; case '+': /* A compound leaper, with two steps one after the other */ ii = 1; index_flags |= 2; break; case '&': /* A compound leaper, with a mask (used to implement "lame leapers") */ /* Define a new type of leaper for the mask. * FIXME: check if this type was already defined and re-use. */ ii = 2; index_flags |= 4; break; } for (int sqr=0; sqr= MAX_LEAPER_TYPES) { printf("Error (too many leapers)\n"); return 0; } for (int sqr = 0; sqr < size; sqr++) leaper[number_of_leapers][sqr] = moves[ii][sqr]; index[ii] = number_of_leapers; number_of_leapers++; } } return (index[0] | (index[1] << 4) | (index[2] << 8) | (index_flags << 12))<<16 | MF_IS_LEAPER; } #define update_leaper_bb(bb,n,m) \ if ( (x+n) >= 0 && (y+m) >= 0 && \ (x+n) < board_files && (y+m) < board_ranks) { \ int dest_sqr = bitboard_t::pack_rank_file(y+m, x+n); \ bb.set(dest_sqr); \ } inline bitboard_t make_aleaper_bitboard(int sqr, int n, int m) const { int board_files = bitboard_t::board_files; int board_ranks = bitboard_t::board_ranks; int x = unpack_file(sqr); int y = unpack_rank(sqr); bitboard_t leaper; update_leaper_bb(leaper, n, m); return leaper; } inline bitboard_t make_leaper_bitboard(int sqr, int n, int m) const { int board_files = bitboard_t::board_files; int board_ranks = bitboard_t::board_ranks; int x = unpack_file(sqr); int y = unpack_rank(sqr); bitboard_t leaper; update_leaper_bb(leaper, n, m); update_leaper_bb(leaper, n,-m); update_leaper_bb(leaper,-n, m); update_leaper_bb(leaper,-n,-m); update_leaper_bb(leaper, m, n); update_leaper_bb(leaper,-m, n); update_leaper_bb(leaper, m,-n); update_leaper_bb(leaper,-m,-n); return leaper; } #undef update_leaper_bb move_flag_t define_stepper(const char *movestr) { const char *s = movestr; uint32_t wstep = 0; uint32_t bstep = 0; /* Dimensions of the board */ int w = bitboard_t::board_files; int h = bitboard_t::board_ranks; if (!movestr) return 0; while (*s && isspace(*s)) s++; if (*s == '\0') return 0; if (strstr(s, "step ") != s) return 0; s+=5; while (*s) { int count = 1; int shift = 0; if (isdigit(*s)) { sscanf(s, "%d", &count); assert(count < 16); assert(count >= 0); s++; } if (strstr(s, "NE") == s) shift = 1; else if (strstr(s, "NW") == s) shift = 7; else if (strstr(s, "SE") == s) shift = 3; else if (strstr(s, "SW") == s) shift = 5; else if (strstr(s, "N") == s) shift = 0; else if (strstr(s, "E") == s) shift = 2; else if (strstr(s, "S") == s) shift = 4; else if (strstr(s, "W") == s) shift = 6; wstep |= count << (4*shift); bstep |= count << (4*inverse_step[shift]); while(*s && *s != ',') s++; if (*s) s++; while (*s && isspace(*s)) s++; } for (int n = 1; n= MAX_STEPPER_TYPES) { return 0; } int index = number_of_steppers; number_of_steppers++; stepper_description[index][WHITE] = wstep; stepper_description[index][BLACK] = bstep; return make_stepper_index(index); } /* TODO: Betza/Mueller notation for piece movement describes moves and * captures in one go, not individually. */ move_flag_t define_betza(const char *movestr) { const char *s = movestr; move_flag_t flags = 0; while (*s) { const char *atom = s; /* Find first upper-case character */ while (*atom && (islower(*atom) || isspace(*atom))) atom++; if (atom != s) { /* TODO: modifiers */ } /* Repeated atoms = riders. * The only ones we implement are WW and FF */ char a = atom[0]; if (atom[1] == atom[0] || atom[1] == '0') { switch (*atom) { case 'W': a = 'R'; break; case 'F': a = 'B'; break; default: return 0; } atom++; } switch (a) { case 'K': /* King = FW */ flags |= define_piece_move("leap (1,0)|(1,1)"); break; case 'Q': /* Queen = RB */ flags |= define_piece_move("slide (H,V,A,D)"); break; case 'R': /* Rook = WW */ flags |= define_piece_move("slide (H,V)"); break; case 'B': /* Bishop = FF */ flags |= define_piece_move("slide (A,D)"); break; case ' ': case 'O': /* No move, or castling */ break; case 'W': /* Wazir = (1,0) */ flags |= define_piece_move("leap (1,0)"); break; case 'F': /* Ferz = (1,1) */ flags |= define_piece_move("leap (1,1)"); break; case 'D': /* Dabbabah = (2,0) */ flags |= define_piece_move("leap (2,0)"); break; case 'N': /* Knight = (2,1) */ flags |= define_piece_move("leap (2,1)"); break; case 'A': /* Alfil = (2, 2) */ flags |= define_piece_move("leap (2,2)"); break; case 'H': /* Threeleaper = (3, 0) */ flags |= define_piece_move("leap (3,0)"); break; case 'C': /* Camel = (3, 1) */ case 'L': flags |= define_piece_move("leap (3,1)"); break; case 'Z': /* Zebra = (3, 2) */ case 'J': flags |= define_piece_move("leap (3,2)"); break; case 'G': /* (3, 3) leaper */ flags |= define_piece_move("leap (3,3)"); break; default: return 0; } s = atom + 1; } return flags; } move_flag_t define_piece_move(const char *movestr) { if (!movestr) return 0; const char *s = movestr; while (isspace(*s)) s++; if (s[0] == '\0') return 0; /* What type of mover is this? */ if (strstr(s, "none ") == s) return 0; if (strstr(s, "slide ") == s) return define_slider(s); if (strstr(s, "hop ") == s) return define_slider(s); if (strstr(s, "step ") == s) return define_stepper(s); if (strstr(s, "aleap ") == s) return define_asymmetric_leaper(s); if (strstr(s, "leap ") == s) return define_symmetric_leaper(s); /* TODO: try to interpret a Betza-like move description and translate * it to what is used internally. */ return 0; } /* Deduce castle flags from king positions and destinations and rook locations. */ void deduce_castle_flags(side_t side, int king_from, int king_to, int rook_from) { /* King-side or queen side? */ bool king_side = (unpack_file(king_to) >= bitboard_t::board_files/2); bitboard_t mask, free, safe; int c, c_first, c_last; int delta = 0; if (unpack_rank(king_from) == unpack_rank(rook_from)) delta = 1; if (unpack_file(king_from) == unpack_file(rook_from)) delta = bitboard_t::board_files; if (bitboard_t::diagonal_nr[king_from] == bitboard_t::diagonal_nr[rook_from]) delta = bitboard_t::board_files+1; if (bitboard_t::anti_diagonal_nr[king_from] == bitboard_t::anti_diagonal_nr[rook_from]) delta = bitboard_t::board_files-1; if (delta == 0) return; int rook_to = king_side ? (king_to - delta) : (king_to + delta); /* It is not enough that the king and rook have a clear path * between them: the path to the destination squares needs to be cleared * as well. * This is implied in normal chess, but not in FRC. */ mask = bitboard_t::square_bitboards[king_from] | bitboard_t::square_bitboards[rook_from]; free.clear(); /* The path of the King */ c_first = std::min(king_from, king_to); c_last = std::max(king_from, king_to); for (c = c_first; c <= c_last; c+=delta) free.set(c); safe = free; /* The path of the Rook */ c_first = std::min(rook_to, rook_from); c_last = std::max(rook_to, rook_from); for (c = c_first; c <= c_last; c+=delta) free.set(c); /* Make sure the king and rook are not marked on the "free" bitboard. * Makes no difference for normal chess, but does affect FRC. */ free &= ~mask; mask &= bitboard_t::board_all; free &= bitboard_t::board_all; safe &= bitboard_t::board_all; if (king_side) { castle_mask[SHORT][side] = mask; castle_free[SHORT][side] = free; castle_safe[SHORT][side] = safe; castle_king_from[SHORT][side] = king_from; castle_king_dest[SHORT][side] = king_to; castle_rook_dest[SHORT][side] = rook_to; } else { castle_mask[LONG][side] = mask; castle_free[LONG][side] = free; castle_safe[LONG][side] = safe; castle_king_from[LONG][side] = king_from; castle_king_dest[LONG][side] = king_to; castle_rook_dest[LONG][side] = rook_to; } } bitboard_t get_all_attackers(const board_t *board, bitboard_t mask, int square) const { bitboard_t occupied = board->get_occupied() & mask; bitboard_t possible_attackers = occupied & super[square]; occupied.set(square); bitboard_t attacked; bitboard_t attacker; for (int n=0; npiece_types->num_piece_types && !possible_attackers.is_empty(); n++) { move_flag_t capture_flags = board->piece_types->piece_capture_flags[n]; for (side_t side = WHITE; side<=BLACK; side++) { bitboard_t bb = possible_attackers & board->bbp[n] & board->bbc[side]; if (bb.is_empty()) continue; possible_attackers ^= bb; /* Steppers */ if (is_stepper(capture_flags)) { int si = get_stepper_index(board->piece_types->piece_capture_flags[n]); int d; for (d=0; d<8; d++) { int max_c = (stepper_description[si][side] >> (d*4)) & 15; bitboard_t captures = bb & super_stepper[square]; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for (int c = 1; c<=max_c && !captures.is_empty(); c++) { captures &= step_mask[d]; captures = captures.sshift(step_shift[d]); captures &= board->piece_types->prison[side][n]; if (captures.test(square)) { attacker.set(square - c*step_shift[d]); break; } captures &= ~occupied; } } } /* Sliders and leapers */ if (is_leaper(capture_flags)) { bitboard_t bp = bb; while (!(bp & super_leaper[square]).is_empty()) { int s = (bp & super_leaper[square]).bitscan(); bp.reset(s); attacked = generate_leaper_move_bitboard(capture_flags, side, s, occupied); attacked &= board->piece_types->prison[side][n]; if (attacked.test(square)) { attacker.set(s); bb.reset(s); } } } #if 0 if (is_slider(capture_flags)) { bitboard_t bp = bb; while (!(bp & super_slider[square]).is_empty()) { int s = (bp & super_slider[square]).bitscan(); bp.reset(s); attacked = generate_slider_move_bitboard(capture_flags, side, s, occupied); attacked &= board->piece_types->prison[side][n]; if (attacked.test(square)) { attacker.set(s); bb.reset(s); } } } #endif if (is_hopper(capture_flags)) { bitboard_t bp = bb; while (!(bp & super_hopper[square]).is_empty()) { int s = (bp & super_hopper[square]).bitscan(); bp.reset(s); attacked = generate_hopper_move_bitboard(capture_flags, side, s, occupied); attacked &= board->piece_types->prison[side][n]; if (attacked.test(square)) { attacker.set(s); bb.reset(s); } } } } } /* Find sliders */ move_flag_t cf[] = { MF_SLIDER_V, MF_SLIDER_H, MF_SLIDER_D, MF_SLIDER_A }; int imax = sizeof cf / sizeof *cf; for (int i=0; i sliders; for (int piece = 0; piecepiece_types->num_piece_types; piece++) { if (board->piece_types->piece_capture_flags[piece] & cf[i]) sliders |= board->bbp[piece]; } sliders &= super_slider[square] & mask; if (sliders.is_empty()) continue; attacker |= sliders & generate_slider_move_bitboard(cf[i], WHITE, square, occupied); } return attacker; } bool player_in_check(const board_t *board, side_t side) const { bitboard_t royal = board->royal & board->bbc[side]; bitboard_t empty; /* If there are no royal pieces, then there is no check */ if (royal.is_empty()) return false; /* If there is more than one king, we can never be in check - unless * the rules say we are when all kings are under attack. */ if (!royal.onebit() && !(board->rule_flags & RF_KING_DUPLECHECK)) return false; move_flag_t *capture_flags = board->piece_types->piece_capture_flags; bitboard_t sup[4]; bitboard_t mask[4]; bitboard_t kmask; bitboard_t bb = royal; while (!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); sup[0] |= super_slider[square]; sup[1] |= super_leaper[square]; sup[2] |= super_stepper[square]; sup[3] |= super_hopper[square]; kmask = super[square] & board->bbc[next_side[side]]; } if (royal.onebit() && kmask.is_empty()) return false; for (int n=0; n<4; n++) sup[n] &= board->bbc[next_side[side]]; for (int n = 0; npiece_types->num_piece_types; n++) { if (is_slider(capture_flags[n])) mask[0] |= sup[0] & board->bbp[n]; if (is_leaper(capture_flags[n])) mask[1] |= sup[1] & board->bbp[n]; if (is_stepper(capture_flags[n])) mask[2] |= sup[2] & board->bbp[n]; if (is_hopper(capture_flags[n])) mask[3] |= sup[3] & board->bbp[n]; } /* Mask out pieces that occur in more than one mask: we only need to * test them once, afterall. */ mask[3] &= ~(mask[0] | mask[1] | mask[2]); mask[2] &= ~(mask[0] | mask[1]); mask[1] &= ~(mask[0]); bitboard_t attacked_squares; /* TODO: we can do one better, at least for sliders and normal * leapers (lame leapers are more tricky): when generating the attack * bitboard, first generate appropriate attacks from the target * square and intersect with the piece type. This allows us to test * against all pieces of the particular type in one go, and we avoid * some possible false positives. */ for (int n=0; n<4; n++) { if (mask[n].is_empty()) continue; attacked_squares |= generate_attack_bitboard(board, empty, mask[n], next_side[side]); if ((attacked_squares & royal) == royal) return true; } if (expect(board->rule_flags & RF_KING_TABOO, false)) { bitboard_t other_king = board->royal & kmask; if (!other_king.is_empty()) { int square = other_king.bitscan(); bitboard_t occ = board->get_occupied(); attacked_squares |= generate_slider_move_bitboard(MF_SLIDER_V, next_side[side], square, occ); } return (attacked_squares & royal) == royal; } return false; } bool was_checking_move(board_t *board, side_t side, move_t lastmove) const { side_t oside = next_side[side]; bitboard_t royal = board->royal & board->bbc[side]; bitboard_t empty; if (royal.is_empty()) return false; if (royal.onebit()) { bitboard_t move_bb; int king = royal.bitscan(); int from = get_move_from(lastmove); int to = get_move_to(lastmove); assert(from < 8*sizeof(kind)); assert(to < 8*sizeof(kind)); move_bb.set(from); move_bb.set(to); if (is_castle_move(lastmove)) { int from = get_castle_move_from2(lastmove); int to = get_castle_move_to2(lastmove); assert(from < 8*sizeof(kind)); assert(to < 8*sizeof(kind)); move_bb.set(from); move_bb.set(to); } if (is_capture_move(lastmove)) { int square = get_move_capture_square(lastmove); assert(square < 8*sizeof(kind)); move_bb.set(square); } if ((super[king] & move_bb).is_empty()) { assert(!player_in_check(board, side)); return false; } else { bitboard_t mask; move_bb.reset(to); if (is_castle_move(lastmove)) { mask.set(get_castle_move_to2(lastmove)); move_bb.reset(get_castle_move_to2(lastmove)); } int king_file = unpack_file(king); int king_rank = unpack_rank(king); int king_diag = bitboard_t::diagonal_nr[king]; int king_anti = bitboard_t::anti_diagonal_nr[king]; while (!move_bb.is_empty()) { int square = move_bb.bitscan(); int file = unpack_file(square); int rank = unpack_rank(square); int diag = bitboard_t::diagonal_nr[square]; int anti = bitboard_t::anti_diagonal_nr[square]; move_bb.reset(square); if (file == king_file) mask |= bitboard_t::board_file[file]; if (rank == king_rank) mask |= bitboard_t::board_rank[rank]; if (diag == king_diag) mask |= bitboard_t::board_diagonal[diag]; if (anti == king_anti) mask |= bitboard_t::board_antidiagonal[anti]; } //bitboard_t sliders; //for (int n = 0; npiece_types->num_piece_types; n++) { // if (board->piece_types->piece_capture_flags[n] & (MF_HOPSLIDE|MF_STEPPER)) // sliders |= board->bbp[n]; //} //mask &= sliders; mask.set(to); /* Possible lame leapers */ mask |= super_leaper[king] & board->bbc[oside]; bitboard_t attacked_squares = generate_attack_bitboard(board, empty, mask, oside); if (attacked_squares.test(king)) return true; assert(!player_in_check(board, side)); return false; } } return player_in_check(board, side); } bitboard_t get_pinned_pieces(const board_t *board, side_t side) const { bitboard_t royal = board->royal & board->bbc[side]; bitboard_t pinned; bitboard_t potential_pins; /* If there is more than one king, or no king at all - ignore pins. */ if (!royal.onebit()) return pinned; int king = royal.bitscan(); potential_pins = board->bbc[side] & super[king]; for (int n = 0; npiece_types->num_piece_types; n++) { bitboard_t atk = board->bbp[n] & board->bbc[next_side[side]] & super[king]; move_flag_t atk_flags = board->piece_types->piece_capture_flags[n]; while(!atk.is_empty()) { int attacker = atk.bitscan(); atk.reset(attacker); /* Sliders */ if (is_slider(atk_flags)) { bitboard_t occ = board->get_occupied(); bitboard_t bb = occ & bitboard_t::board_between[king][attacker]; bb &= generate_slider_move_bitboard(atk_flags, next_side[side], attacker, occ & ~bb); if (bb.onebit()) pinned |= bb&potential_pins; } /* Hoppers */ if (is_hopper(atk_flags)) { bitboard_t occ = board->get_occupied(); bitboard_t bb = occ & bitboard_t::board_between[king][attacker]; bb &= generate_slider_move_bitboard(atk_flags>>4, next_side[side], attacker, occ & ~bb); if (bb.twobit()) pinned |= bb&potential_pins; } /* TODO: multi-steppers */ /* Lame leapers */ if (is_leaper(atk_flags) && is_masked_leaper(atk_flags) && is_double_leaper(atk_flags)) { bitboard_t occ = board->get_occupied(); bitboard_t atk = generate_leaper_move_bitboard(atk_flags, next_side[side], attacker, occ); if (!atk.test(king)) { int index = get_leaper_index(atk_flags); potential_pins &= leaper[index][attacker]; while (!potential_pins.is_empty()) { int square = potential_pins.bitscan(); potential_pins.reset(square); occ.reset(square); atk = generate_leaper_move_bitboard(atk_flags, next_side[side], attacker, occ); if (atk.test(king)) { pinned.set(square); break; } } } } } } return pinned; } template void generate_stepper_moves_mask_for_piece(movelist_t *movelist, const board_t *board, int piece, move_flag_t move_flags, uint16_t piece_flags, piece_description_t *piece_types, bitboard_t from_bb, bitboard_t destination_mask, bitboard_t occupied, bitboard_t promotion_zone, bitboard_t optional_promotion_zone, side_t side_to_move, piece_bit_t allowed_promotion_pieces) const { move_t move; /* Check for stepper moves, which are generated in parallel */ if (is_stepper(move_flags)) { int si = get_stepper_index(move_flags); for (int d=0; d<8; d++) { /* Loop over all directions */ int max_c = (stepper_description[si][side_to_move] >> (d*4)) & 15; bitboard_t moves = from_bb; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for (int c = 1; c<=max_c; c++) { moves &= step_mask[d]; moves = moves.sshift(step_shift[d]); moves &= ~occupied; moves &= board->piece_types->prison[side_to_move][neutral_piece(piece)]; /* Scan all bits */ bitboard_t bb = moves & destination_mask; while (!bb.is_empty()) { int to = bb.bitscan(); int from = to - c*step_shift[d]; bb.reset(to); /* Check for promotions * When the piece moves into the promotion zone, it will get promoted to one of the allowed * promotion pieces, which can be different for each piece type (and further restricted, for * instance during Q-search). * Promotion to a royal piece is only allowed if the number of royal pieces a player has is * smaller than the maximum number of royal pieces. */ if (promotion_zone.test(to) || (promotion_zone.test(from) && !(board->rule_flags & RF_PROMOTE_IN_PLACE))) { piece_bit_t c = allowed_promotion_pieces; while (c) { int tpiece = bitscan32(c); c ^= 1<piece_maximum[tpiece][side_to_move] == 128 || board->piece_count(tpiece, side_to_move) < piece_types->piece_maximum[tpiece][side_to_move]) { tpiece = piece_for_side(tpiece, side_to_move); move = encode_normal_promotion(piece, from, to, tpiece); movelist->push(move); } } /* If promotions are optional, we also encode a normal move */ if (optional_promotion_zone.test(to) || (optional_promotion_zone.test(from) && !promotion_zone.test(to) )) { move = encode_normal_move(piece, from, to); if (special && c>1 && piece_flags & PF_SET_EP) move |= MOVE_SET_ENPASSANT; if (piece_flags & PF_NORET) move |= MOVE_RESET50; movelist->push(move); } } else { move = encode_normal_move(piece, from, to); if (special && c>1 && piece_flags & PF_SET_EP) move |= MOVE_SET_ENPASSANT; if (piece_flags & PF_NORET) move |= MOVE_RESET50; movelist->push(move); } } } } } } template void generate_stepper_captures_mask_for_piece(movelist_t *movelist, const board_t *board, int piece, move_flag_t move_flags, uint16_t /* piece_flags */, piece_description_t *piece_types, bitboard_t from_bb, bitboard_t destination_mask, bitboard_t occupied, bitboard_t enemy, bitboard_t ep_dest, bitboard_t promotion_zone, bitboard_t optional_promotion_zone, side_t side_to_move, piece_bit_t allowed_promotion_pieces) const { move_t move; /* Check for stepper moves, which are generated in parallel */ if (is_stepper(move_flags)) { int si = get_stepper_index(move_flags); for (int d=0; d<8; d++) { /* Loop over all directions */ int max_c = (stepper_description[si][side_to_move] >> (d*4)) & 15; bitboard_t captures = from_bb; /* We have a repetition count, so we do a number of steps one after the other. * This can effectively duplicate a slider. */ for (int c = 1; c<=max_c; c++) { captures &= step_mask[d]; captures = captures.sshift(step_shift[d]); captures &= board->piece_types->prison[side_to_move][neutral_piece(piece)]; /* Scan all bits */ bitboard_t bb = captures & (enemy | ep_dest) & destination_mask; while (!bb.is_empty()) { int to = bb.bitscan(); int from = to - c*step_shift[d]; int ptaken = piece_for_side(board->get_piece(to), next_side[side_to_move]); bb.reset(to); /* Check for promotions * When the piece moves into the promotion zone, it will get promoted to one of the allowed * promotion pieces, which can be different for each piece type (and further restricted, for * instance during Q-search). * Promotion to a royal piece is only allowed if the number of royal pieces a player has is * smaller than the maximum number of royal pieces. */ if (promotion_zone.test(to) || promotion_zone.test(from)) { piece_bit_t c = allowed_promotion_pieces; while (c) { int tpiece = bitscan32(c); c ^= 1<piece_maximum[tpiece][side_to_move] == 128 || board->piece_count(tpiece, side_to_move) < piece_types->piece_maximum[tpiece][side_to_move]) { tpiece = piece_for_side(tpiece, side_to_move); move = encode_capture_promotion(piece, from, to, ptaken, tpiece); if (capture_to_holdings) { int pstore = piece_types->demotion[board->get_piece(to)]; side_t store_side = NONE; if (board->rule_flags & RF_KEEP_CAPTURE) store_side = side_to_move; if (board->rule_flags & RF_RETURN_CAPTURE) store_side = next_side[side_to_move]; assert(store_side != NONE); move = add_move_store(move, piece_for_side(pstore, store_side), 1); } movelist->push(move); } } /* If promotions are optional, we also encode a normal move */ if (optional_promotion_zone.test(to) || (optional_promotion_zone.test(from) && !promotion_zone.test(to) )) { if (ep_dest.test(to)) { int ptaken = piece_for_side(board->get_piece(board->ep_victim), next_side[side_to_move]); move = encode_en_passant_capture(piece, from, to, ptaken, board->ep_victim); } else { move = encode_normal_capture(piece, from, to, ptaken); } if (capture_to_holdings) { int pstore = piece_types->demotion[board->get_piece(to)]; side_t store_side = NONE; if (board->rule_flags & RF_KEEP_CAPTURE) store_side = side_to_move; if (board->rule_flags & RF_RETURN_CAPTURE) store_side = next_side[side_to_move]; assert(store_side != NONE); move = add_move_store(move, piece_for_side(pstore, store_side), 1); } movelist->push(move); } } else { if (ep_dest.test(to)) { int ptaken = piece_for_side(board->get_piece(board->ep_victim), next_side[side_to_move]); move = encode_en_passant_capture(piece, from, to, ptaken, board->ep_victim); } else { move = encode_normal_capture(piece, from, to, ptaken); } if (capture_to_holdings) { int pstore = piece_types->demotion[board->get_piece(to)]; side_t store_side = NONE; if (board->rule_flags & RF_KEEP_CAPTURE) store_side = side_to_move; if (board->rule_flags & RF_RETURN_CAPTURE) store_side = next_side[side_to_move]; assert(store_side != NONE); move = add_move_store(move, piece_for_side(pstore, store_side), 1); } movelist->push(move); } } captures &= ~occupied; } } } } template void do_generate_moves_mask(movelist_t *movelist, const board_t *board, bitboard_t source_mask, bitboard_t destination_mask, side_t side_to_move, uint32_t allowed_promotion_pieces, uint32_t allowed_drop_pieces, uint32_t allowed_piece_deferrals) const { piece_description_t *piece_types; move_flag_t *piece_capture_flags; move_flag_t *piece_move_flags; move_flag_t *special_move_flags; bitboard_t own, enemy, own_movers; bitboard_t occupied; bitboard_t attacked; move_t move; int n; assert(!player_in_check(board, next_side[side_to_move])); piece_types = board->piece_types; piece_capture_flags = piece_types->piece_capture_flags; piece_move_flags = piece_types->piece_move_flags; special_move_flags = piece_types->piece_special_move_flags; /* Bookkeeping: we keep a pointer to the next move in the move list, and * update the number of moves in the list at the end of this function */ own = board->bbc[side_to_move]; enemy = board->bbc[next_side[side_to_move]]; occupied = own | enemy; own_movers = own & source_mask; bitboard_t movers = own_movers; /* Generate drops */ if (generate_drops && allowed_drop_pieces && (board->rule_flags & (RF_ALLOW_DROPS | RF_FORCE_DROPS))) { bool dropped = false; for (n=0; nnum_piece_types; n++) { if (board->holdings[n][side_to_move] && (allowed_drop_pieces & (1 << n))) { dropped = true; int piece = piece_for_side(n, side_to_move); bitboard_t drops = destination_mask & ~occupied & piece_types->drop_zone[side_to_move][n]; if (piece_types->piece_flags[n] & PF_DROPONEFILE) { for (int f = 0; f::board_files; f++) { bitboard_t bb = own & board->bbp[n] & bitboard_t::board_file[f]; if (!bb.is_empty()) if (piece_types->piece_drop_file_maximum[n] < 2 || bb.popcount() >= piece_types->piece_drop_file_maximum[n]) drops &= ~bitboard_t::board_file[f]; } } while (!drops.is_empty()) { int to = drops.bitscan(); drops.reset(to); move = encode_drop_move(piece, to); move = add_move_retrieve(move, piece, 1); movelist->push(move); if (board->rule_flags & RF_PROMOTE_ON_DROP) { piece_bit_t c = piece_types->piece_promotion_choice[n] & allowed_promotion_pieces; while (c) { int tpiece = bitscan32(c); c ^= 1<piece_maximum[tpiece][side_to_move] == 128 || board->piece_count(tpiece, side_to_move) < piece_types->piece_maximum[tpiece][side_to_move]) { tpiece = piece_for_side(tpiece, side_to_move); move = encode_drop_move(tpiece, to); move = add_move_retrieve(move, piece, 1); movelist->push(move); } } } } } } /* Break out early if drops are possible and are forced if possible; no other moves are legal. */ if (dropped && (board->rule_flags & RF_FORCE_DROPS)) goto done; } /* Generate lifts */ if (generate_pickup && generate_drops && allowed_drop_pieces && !board->check() && (board->rule_flags & RF_ALLOW_PICKUP)) { for (n=0; nnum_piece_types; n++) { if (piece_types->piece_flags[n] & PF_ROYAL) continue; bitboard_t lift = own_movers & board->bbp[n]; if (!lift.is_empty() && (allowed_drop_pieces & (1 << n))) { int piece = piece_for_side(n, side_to_move); while (!lift.is_empty()) { int from = lift.bitscan(); lift.reset(from); move = encode_pickup_move(piece, from); move = add_move_store(move, piece, 1); movelist->push(move); } } } } /* Now generate moves for all pieces; only scan our own pieces. This mainly helps variants with different * armies. * We generate all moves for a particular piece-type first. */ for (n=0; nnum_piece_types && !movers.is_empty(); n++) { if ((movers & board->bbp[n]).is_empty()) continue; movers &= ~board->bbp[n]; bitboard_t special_zone = piece_types->special_zone[side_to_move][n]; if (board->rule_flags & RF_SPECIAL_IS_INIT) special_zone &= board->init; bitboard_t ep_dest; if (piece_types->piece_flags[n] & PF_TAKE_EP) ep_dest = board->ep; bitboard_t promotion_zone = piece_types->promotion_zone[side_to_move][n]; bitboard_t optional_promotion_zone = piece_types->optional_promotion_zone[side_to_move][n]; bitboard_t bb = own_movers & board->bbp[n]; int piece = piece_for_side(n, side_to_move); /* In-place promotions */ if (promote_in_place && !(bb & optional_promotion_zone).is_empty()) { bitboard_t bp = bb & optional_promotion_zone; while (!bp.is_empty()) { int square = bp.bitscan(); bp.reset(square); piece_bit_t c = piece_types->piece_promotion_choice[n] & allowed_promotion_pieces; while (c) { int tpiece = bitscan32(c); c ^= 1<piece_maximum[tpiece][side_to_move] == 128 || board->piece_count(tpiece, side_to_move) < piece_types->piece_maximum[tpiece][side_to_move]) { tpiece = piece_for_side(tpiece, side_to_move); move = encode_normal_promotion(piece, square, square, tpiece); movelist->push(move); } } } } /* Generate stepper moves, in parallel */ generate_stepper_moves_mask_for_piece(movelist, board, piece, piece_move_flags[n], piece_types->piece_flags[n], piece_types, bb & ~special_zone, destination_mask, occupied, promotion_zone, optional_promotion_zone, side_to_move, piece_types->piece_promotion_choice[n] & allowed_promotion_pieces); generate_stepper_moves_mask_for_piece(movelist, board, piece, special_move_flags[n], piece_types->piece_flags[n], piece_types, bb & special_zone, destination_mask, occupied, promotion_zone, optional_promotion_zone, side_to_move, piece_types->piece_promotion_choice[n] & allowed_promotion_pieces); generate_stepper_captures_mask_for_piece(movelist, board, piece, piece_capture_flags[n], piece_types->piece_flags[n], piece_types, bb, destination_mask, occupied, enemy, ep_dest, promotion_zone, optional_promotion_zone, side_to_move, piece_types->piece_promotion_choice[n] & allowed_promotion_pieces); /* Castling * Because of the hassle when doing legality testing, we explicitly test whether castling is allowed in * the current position by testing for attacks on any of the critical squares. This is a hassle and * potentially slow, but only if castling may be possible in the current position. */ if (expect(piece_types->piece_flags[n] & PF_CASTLE, false) && !(board->init&bb).is_empty()) { for (int c = SHORT; cinit & castle_mask[c][side_to_move]) == castle_mask[c][side_to_move]) { if (castle_free[c][side_to_move].is_empty() || ((occupied & castle_free[c][side_to_move]).is_empty() && !(destination_mask & castle_free[c][side_to_move]).is_empty())) { bitboard_t test = castle_safe[c][side_to_move]; bitboard_t mask = generate_super_attacks_for_squares(test, super); bitboard_t attacked_squares = generate_attack_bitboard(board, test, mask, next_side[side_to_move]); if ((attacked_squares & castle_safe[c][side_to_move]).is_empty()) { int from1 = (castle_mask[c][side_to_move] & bb).bitscan(); int from2 = (castle_mask[c][side_to_move] & ~bb).bitscan(); int piece2 = piece_for_side(board->get_piece(from2), side_to_move); int to1 = castle_king_dest[c][side_to_move]; int to2 = castle_rook_dest[c][side_to_move]; move = encode_castle_move(piece, from1, to1, piece2, from2, to2); movelist->push(move); } } } } } /* Now determine slider and leaper moves for this piece type - if it has any */ if ( (piece_move_flags[n] | piece_capture_flags[n] | special_move_flags[n]) & (MF_SLIDER|MF_HOPPER|MF_IS_LEAPER) ) { while (!bb.is_empty()) { bitboard_t moves; bitboard_t captures; int from = bb.bitscan(); bb.reset(from); move_flag_t move_flags = piece_move_flags[n]; move_flag_t capture_flags = piece_capture_flags[n]; if (special_zone.test(from)) move_flags = special_move_flags[n]; move_flags &= (MF_SLIDER | MF_HOPPER | MF_LEAPER_FLAGS); capture_flags &= (MF_SLIDER | MF_HOPPER | MF_LEAPER_FLAGS); if (is_leaper(move_flags)) moves |= generate_leaper_move_bitboard(move_flags, side_to_move, from, occupied); if (is_slider(move_flags)) moves |= generate_slider_move_bitboard(move_flags, side_to_move, from, occupied); if (is_hopper(move_flags)) moves |= generate_hopper_move_bitboard(move_flags, side_to_move, from, occupied); moves &= piece_types->prison[side_to_move][n]; /* Optimise the common case where pieces move the same way * they capture. */ if (capture_flags == move_flags) { captures = moves; } else { if (is_leaper(capture_flags)) captures |= generate_leaper_move_bitboard(capture_flags, side_to_move, from, occupied); if (is_slider(capture_flags)) captures |= generate_slider_move_bitboard(capture_flags, side_to_move, from, occupied); if (is_hopper(capture_flags)) captures |= generate_hopper_move_bitboard(capture_flags, side_to_move, from, occupied); captures &= piece_types->prison[side_to_move][n]; } /* Pass */ if (moves.test(from)) { move_t move = encode_normal_move(piece, from, from); movelist->push(move); } /* Mask out occupied squares from normal moves, only capture enemy pieces */ moves &= ~occupied; captures &= enemy; moves &= destination_mask; captures &= destination_mask; /* Serialise moves * We separate out the promotion moves and options and * serialise those in a separate loop. */ bitboard_t pmoves = moves & (promotion_zone & ~optional_promotion_zone); bitboard_t pcaptures = captures & (promotion_zone & ~optional_promotion_zone); moves ^= pmoves; captures ^= pcaptures; pmoves |= moves & optional_promotion_zone; pcaptures |= captures & optional_promotion_zone; /* Also include moves that originate in the promotion zone. */ if (promotion_zone.test(from)) { pmoves |= moves; pcaptures |= captures; if (!optional_promotion_zone.test(from)) { moves.clear(); captures.clear(); } } if (!(allowed_piece_deferrals & (1<push(move); } while (!captures.is_empty()) { int to = captures.bitscan(); int ptaken = piece_for_side(board->get_piece(to), next_side[side_to_move]); captures.reset(to); move = encode_normal_capture(piece, from, to, ptaken); if (capture_to_holdings) { int pstore = piece_types->demotion[board->get_piece(to)]; side_t store_side = NONE; if (board->rule_flags & RF_KEEP_CAPTURE) store_side = side_to_move; if (board->rule_flags & RF_RETURN_CAPTURE) store_side = next_side[side_to_move]; assert(store_side != NONE); move = add_move_store(move, piece_for_side(pstore, store_side), 1); } movelist->push(move); } /* Promotions */ while (!pmoves.is_empty()) { int to = pmoves.bitscan(); pmoves.reset(to); piece_bit_t c = piece_types->piece_promotion_choice[n] & allowed_promotion_pieces; while (c) { int tpiece = bitscan32(c); c ^= 1<piece_maximum[tpiece][side_to_move] == 128 || board->piece_count(tpiece, side_to_move) < piece_types->piece_maximum[tpiece][side_to_move]) { tpiece = piece_for_side(tpiece, side_to_move); move = encode_normal_promotion(piece, from, to, tpiece); movelist->push(move); } } } while (!pcaptures.is_empty()) { int to = pcaptures.bitscan(); int ptaken = piece_for_side(board->get_piece(to), next_side[side_to_move]); pcaptures.reset(to); piece_bit_t c = piece_types->piece_promotion_choice[n] & allowed_promotion_pieces; while (c) { int tpiece = bitscan32(c); c ^= 1<piece_maximum[tpiece][side_to_move] == 128 || board->piece_count(tpiece, side_to_move) < piece_types->piece_maximum[tpiece][side_to_move]) { tpiece = piece_for_side(tpiece, side_to_move); move = encode_capture_promotion(piece, from, to, ptaken, tpiece); if (capture_to_holdings) { int pstore = piece_types->demotion[board->get_piece(to)]; side_t store_side = NONE; if (board->rule_flags & RF_KEEP_CAPTURE) store_side = side_to_move; if (board->rule_flags & RF_RETURN_CAPTURE) store_side = next_side[side_to_move]; assert(store_side != NONE); move = add_move_store(move, piece_for_side(pstore, store_side), 1); } movelist->push(move); } } } } } } done: return; } template void do_generate_moves_mask_inplace(movelist_t *ml, const board_t *board, bitboard_t from, bitboard_t to, side_t stm, uint32_t allowed_prom, uint32_t allowed_drop, uint32_t allowed_defer) const { if (board->rule_flags & RF_PROMOTE_IN_PLACE) do_generate_moves_mask(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); else do_generate_moves_mask(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); } template void do_generate_moves_mask_pickup(movelist_t *ml, const board_t *board, bitboard_t from, bitboard_t to, side_t stm, uint32_t allowed_prom, uint32_t allowed_drop, uint32_t allowed_defer) const { if ((board->rule_flags & RF_ALLOW_PICKUP)) do_generate_moves_mask_inplace(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); else do_generate_moves_mask_inplace(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); } template void do_generate_moves_mask_hold(movelist_t *ml, const board_t *board, bitboard_t from, bitboard_t to, side_t stm, uint32_t allowed_prom, uint32_t allowed_drop, uint32_t allowed_defer) const { /* If we don't use drop rules, we don't update holdings. */ if (!drop_rules) { do_generate_moves_mask_pickup(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); return; } if (!quiesc_only) { if (board->rule_flags & RF_USE_CAPTURE) do_generate_moves_mask_pickup(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); else do_generate_moves_mask_pickup(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); } else { bitboard_t oking = board->royal & board->bbc[next_side[stm]]; bitboard_t king_zone; if (oking.onebit()) king_zone = bitboard_t::neighbour_board[oking.bitscan()]; if (board->rule_flags & RF_USE_CAPTURE) { do_generate_moves_mask_pickup(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); //do_generate_moves_mask_pickup(ml, board, from, king_zone, stm, allowed_prom, allowed_drop, allowed_defer); } else { do_generate_moves_mask_pickup(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); //do_generate_moves_mask_pickup(ml, board, from, king_zone, stm, allowed_prom, allowed_drop, allowed_defer); } } } template void do_generate_moves_mask_quiesc(movelist_t *ml, const board_t *board, bitboard_t from, bitboard_t to, side_t stm, uint32_t allowed_prom, uint32_t allowed_drop, uint32_t allowed_defer) const { if (board->rule_flags & RF_USE_DROPS) { do_generate_moves_mask_hold(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); } else do_generate_moves_mask_hold(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); } inline void generate_moves_mask(movelist_t *ml, const board_t *board, bitboard_t from, bitboard_t to, side_t stm, uint32_t allowed_prom, uint32_t allowed_drop, uint32_t allowed_defer, bool quiesc_only = false) const { if (quiesc_only) do_generate_moves_mask_quiesc(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); else do_generate_moves_mask_quiesc(ml, board, from, to, stm, allowed_prom, allowed_drop, allowed_defer); } /* Generate pseudo-legal check evasions. This is mainly useful in that * it removes most illegal moves. It may not catch all of them though, * depending on rules and piece moves in a particular variant. */ bool generate_evasions(movelist_t *movelist, const board_t *board, side_t side_to_move) const { assert(board->check()); bitboard_t destination = bitboard_t::board_all; bitboard_t origin = bitboard_t::board_all; bitboard_t attacker, bb, kings, pinned, occ, destest, safe; kings = board->royal & board->bbc[side_to_move]; occ = board->get_occupied(); /* FIXME: if there are multiple kings we get duplicate moves in the * movelist. */ if (!kings.onebit()) return false; movelist->num_moves = 0; /* Identify attacking pieces */ bb = kings; while (!bb.is_empty()) { int king = bb.bitscan(); bb.reset(king); attacker |= get_all_attackers(board, occ, king); } assert(!attacker.is_empty()); attacker &= ~board->bbc[side_to_move]; /* Evasions */ if (kings.onebit()) { safe = destination; safe &= ~generate_attack_bitboard_mask(board, bitboard_t::board_empty, attacker, ~kings, next_side[side_to_move]); generate_moves_mask(movelist, board, kings, safe, side_to_move, ~0, 0, ~0); } else { bb = kings; while (!bb.is_empty()) { bitboard_t king_bb; int king = bb.bitscan(); bb.reset(king); king_bb.set(king); safe = destination; safe &= ~generate_attack_bitboard_mask(board, king_bb, attacker, ~king_bb, side_to_move); generate_moves_mask(movelist, board, king_bb, safe, side_to_move, ~0, 0, ~0); } } /* Evacuate interposing pieces acting as a cannon mount */ for (int n=0; npiece_types->num_piece_types; n++) { move_flag_t atk_flags = board->piece_types->piece_capture_flags[n]; if (!is_hopper(atk_flags)) continue; bb = attacker & board->bbp[n]; while (!bb.is_empty()) { int square = bb.bitscan(); bb.reset(square); bitboard_t king_bb = kings; while (!king_bb.is_empty()) { int king = king_bb.bitscan(); king_bb.reset(king); bitboard_t from_bb = bitboard_t::board_between[king][square]; generate_moves_mask(movelist, board, from_bb, ~attacker, side_to_move, ~0, ~0, ~0); } } } /* Captures of attacking pieces */ generate_moves_mask(movelist, board, origin^kings, attacker, side_to_move, ~0, 0, ~0); destest |= attacker; /* En-passant captures */ if (board->ep_victim && attacker.test(board->ep_victim)) { bitboard_t bb = board->ep; generate_moves_mask(movelist, board, origin^kings, bb, side_to_move, ~0, 0, ~0); } /* Interpose */ bb = kings; pinned = get_pinned_pieces(board, side_to_move); while (!bb.is_empty()) { int king = bb.bitscan(); bb.reset(king); bitboard_t bp = attacker; while (!bp.is_empty()) { int square = bp.bitscan(); int piece = board->get_piece(square); bp.reset(square); bitboard_t destination = bitboard_t::board_between[king][square] & ~occ; if (!destination.is_empty()) generate_moves_mask(movelist, board, origin^(kings | pinned), destination, side_to_move, ~0, ~0, ~0); else if (is_masked_leaper(board->piece_types->piece_capture_flags[piece])) { /* Block a lame leaper */ int index = get_leaper_index(board->piece_types->piece_capture_flags[piece]); destination = leaper[index][square] & ~occ; generate_moves_mask(movelist, board, origin^(kings | pinned), destination, side_to_move, ~0, ~0, ~0); } destest |= destination; } } /* Promotion to king, if promotion to king is allowed */ for (int n = 0; npiece_types->num_piece_types; n++) { if (!(board->piece_types->piece_promotion_choice[n] & board->piece_types->royal_pieces)) continue; if ((board->bbp[n] & board->bbc[side_to_move]).is_empty()) continue; bitboard_t from_mask = board->bbp[n]&(~pinned); bitboard_t to_mask = destination & (~destest | board->piece_types->promotion_zone[side_to_move][n]); if (!to_mask.is_empty() && !from_mask.is_empty()) generate_moves_mask(movelist, board, from_mask, to_mask, side_to_move, (~0) & board->piece_types->royal_pieces, 0, ~0); } return true; } /* Add gating moves to the move list. * Intended for Seirawan chess. */ void generate_gate_moves(movelist_t *movelist, const board_t *board, side_t side_to_move) const { bitboard_t king = board->royal & board->bbc[side_to_move]; bitboard_t rank = bitboard_t::board_north_edge; int n_last, n; if (side_to_move == WHITE) rank = bitboard_t::board_south_edge; /* We only care about pieces that have not yet moved */ if ((rank & board->init).is_empty()) return; /* If the holdings are empty, there is nothing to do here */ uint32_t gate_mask = 0; for (int n=0; npiece_types->num_piece_types; n++) if (board->holdings[n][side_to_move]) gate_mask |= 1< pinned = get_pinned_pieces(board, side_to_move); pinned &= rank & board->init; if (!pinned.is_empty()) { /* Filter out moves of pinned pieces that are not along the same rank: * they are illegal because they expose the king to check. */ n_last = movelist->num_moves-1; n = 0; while (nnum_moves) { move_t move = movelist->move[n]; bitboard_t from = bitboard_t::square_bitboards[get_move_from(move)]; bitboard_t to = bitboard_t::square_bitboards[get_move_to(move)]; if (!(pinned & from).is_empty() && (rank & to).is_empty()) { movelist->move[n] = movelist->move[n_last]; movelist->move[n_last] = move; movelist->num_moves--; n_last--; } n++; } } /* Go through the move list and add appropriate gating moves */ n_last = movelist->num_moves; for (n=0; nmove[n]; int from = get_move_from(base); bitboard_t bb_from = bitboard_t::square_bitboards[from]; if (!(bb_from & rank & board->init).is_empty()) { for (int n=0; npiece_types->num_piece_types; n++) { if (board->holdings[n][side_to_move] == 0) continue; int tpiece = piece_for_side(n, side_to_move); movelist->push(add_move_gate(base, tpiece, from) | MOVE_RESET50); } } if (is_castle_move(base)) { int from = get_castle_move_from2(base); bitboard_t bb_from = bitboard_t::square_bitboards[from]; for (int n=0; npiece_types->num_piece_types; n++) { if (board->holdings[n][side_to_move] == 0) continue; int tpiece = piece_for_side(n, side_to_move); movelist->push(add_move_gate(base, tpiece, from) | MOVE_RESET50); } } } } void generate_moves(movelist_t *movelist, const board_t *board, side_t side_to_move, bool quiesc_only = false, uint32_t allowed_piece_deferrals = ~0) const { bitboard_t destination = bitboard_t::board_all; bitboard_t origin = bitboard_t::board_all; /* If we are in check, then only generate moves in/to the area that can be reached by a superpiece standing * in the location of the king(s). These will be the only candidates for resolving the check, all other * moves will be pruned anyway. */ if (board->check()) { if (generate_evasions(movelist, board, side_to_move)) goto finalise; else { bitboard_t royal = board->royal & board->bbc[side_to_move]; assert(!royal.is_empty()); destination = generate_super_attacks_for_squares(royal, super); quiesc_only = false; } } else if (quiesc_only) { destination = board->bbc[next_side[side_to_move]]; } movelist->num_moves = 0; generate_moves_mask(movelist, board, origin, destination, side_to_move, ~0, ~0, allowed_piece_deferrals, quiesc_only); if (quiesc_only) { for (int n=0; npiece_types->num_piece_types; n++) { destination = board->piece_types->promotion_zone[side_to_move][n] & ~board->bbc[next_side[side_to_move]]; origin = board->bbp[n] & board->bbc[side_to_move]; if (destination.is_empty()) continue; if (origin.is_empty()) continue; generate_moves_mask(movelist, board, origin, destination, side_to_move, ~0, 0, allowed_piece_deferrals, quiesc_only); } } finalise: if ( (board->rule_flags & RF_GATE_DROPS) && !(board->init & board->bbc[side_to_move] & (bitboard_t::board_south_edge | bitboard_t::board_north_edge)).is_empty()) { generate_gate_moves(movelist, board, side_to_move); } return; } stage_t generate_staged_moves(stage_t stage, movelist_t *movelist, const board_t *board, side_t side_to_move) const { movelist->clear(); if (stage == STAGE_DONE) return stage; side_t oside = next_side[side_to_move]; bitboard_t oking = board->royal & board->bbc[oside]; bitboard_t occ = board->get_occupied(); uint32_t defer = board->piece_types->deferral_allowed; switch (stage) { /* Normal move generation (TODO) */ case STAGE_DROP: break; case STAGE_NORMAL: break; /* Mate/Tsume search */ case STAGE_CHECKING_DROP: if (oking.onebit()) for (int n = 0; npiece_types->num_piece_types; n++) { if (board->holdings[n][side_to_move]) { move_flag_t mf = board->piece_types->piece_capture_flags[n]; bitboard_t check_mask = generate_move_bitboard_for_flags(mf, oking.bitscan(), occ, oside); generate_moves_mask(movelist, board, bitboard_t::board_empty, check_mask, side_to_move, 0, 1<piece_types->num_piece_types; n++) { if ( !(board->bbp[n] & board->bbc[side_to_move]).is_empty() ) { move_flag_t mf = board->piece_types->piece_capture_flags[n]; bitboard_t check_mask = generate_move_bitboard_for_flags(mf, oking.bitscan(), occ, oside); generate_moves_mask(movelist, board, board->bbp[n], check_mask, side_to_move, 0, 0, defer); } } break; /* Evasion generation */ case STAGE_CHECK_EVADE: generate_moves(movelist, board, side_to_move, defer); break; case STAGE_DONE: break; } return next_stage[stage]; } void generate_chase_candidates(movelist_t *movelist, const board_t *board, side_t side_to_move) const { assert(board->rule_flags & RF_USE_CHASERULE); bitboard_t destination = board->bbc[next_side[side_to_move]]; bitboard_t origin = bitboard_t::board_all; bitboard_t self = bitboard_t::board_north; bitboard_t other = bitboard_t::board_north; if (side_to_move == BLACK) { self = bitboard_t::board_north; other = bitboard_t::board_south; } for (int n = 0; npiece_types->num_piece_types; n++) { if (board->piece_types->royal_pieces & (1 << n)) origin &= ~board->bbp[n]; if (board->piece_types->defensive_pieces & (1 << n)) origin &= ~board->bbp[n]; if (board->piece_types->pawn_pieces & (1 << n)) origin &= ~(board->bbp[n] & self); if (board->piece_types->pawn_pieces & (1 << n)) destination &= ~(board->bbp[n] & other); } movelist->num_moves = 0; generate_moves_mask(movelist, board, origin, destination, side_to_move, ~0, ~0, ~0); } }; #endif SjaakII/include/movelist.h000644 000765 000024 00000005775 12437601674 016555 0ustar00eglebbkstaff000000 000000 #ifndef MOVELIST_H #define MOVELIST_H #include "move.h" /* datastructure to hold the number of legal moves in a position */ #define MAX_MOVES 256 typedef struct movelist_t { move_t *move; int *score; int num_moves; int cur_move; int max_moves; movelist_t () { cur_move = num_moves = 0; max_moves = MAX_MOVES; move = (move_t *)malloc(max_moves * sizeof *move); score = (int *)malloc(max_moves * sizeof *score); } ~movelist_t() { free(move); free(score); } void clear() { cur_move = num_moves = 0; } void push(move_t m) { move[num_moves++] = m; if (num_moves >= max_moves) { max_moves += MAX_MOVES; move = (move_t *)realloc(move, max_moves * sizeof *move); score = (int *)realloc(score, max_moves * sizeof *score); } } void print() const { for (int n=0; n 0); assert(cur_move-1 < num_moves); return score[cur_move-1]; } void set_move_score(int s) { assert(cur_move > 0); assert(cur_move-1 < num_moves); score[cur_move-1] = s; } void rewind() { cur_move = 0; } move_t next_move() { move_t m = 0; if (cur_move < num_moves) { int nm = cur_move; int sv = score[nm]; int n; for (n=cur_move+1; n score[nm]) nm = n; } n = cur_move; m = move[n]; move[n] = move[nm]; move[nm] = m; sv = score[n]; score[n] = score[nm]; score[nm] = sv; m = move[cur_move]; cur_move++; } return m; } /* A bit of syntactic sugar: define a functor so we can call movelist() * instead of movelist.next_move(). * Then if we call it "movelist_t next_move" we can write "move = * next_move()". * Perhaps this is not quite the same as readable code... */ move_t operator()() { return next_move(); } void sort() { } /* Returns the index in the movelist of a valid move corresponding to the * given origin/destination. Intended for player interaction. * Returns -1 if no moves in the list match (ie, the requested move is * invalid). In the case of a promotion, there will be more than one move * that matches. */ int validate_move(int from, int to, int ppiece = MAX_PIECE_TYPES) const { int n; for (n=0; n::board_files*bitboard_t::board_ranks; movelist_t movelist; int src = 0, dest = 0, ppiece = 0; char *s; int n; /* First, generate the list of moves for this position */ if (external_movelist) { movelist.clear(); for(int n = 0; nnum_moves; n++) movelist.push(external_movelist->move[n]); } else { generate_legal_moves(&movelist); } while (isspace(*move_str) && *move_str) move_str++; char ms[16]; snprintf(ms, sizeof(ms), "%s", move_str); s = strstr(ms, "="); if (s) { while (*s) { *s = *(s+1); s++; } } for (int n = 0; n. */ int add_piece_type(move_flag_t move_flags, move_flag_t capture_flags, uint16_t piece_flags, const bitboard_t promotion_zone[2], const char *promotion_string, const char *name, const char *symbol, const char *notation, int value = 0) { if (pt.num_piece_types>=MAX_PIECE_TYPES) return -1; if (!promotion_string) promotion_string = ""; if (!name) name = ""; if (!symbol) symbol = ""; if (!notation) notation = ""; int n = pt.num_piece_types; free(pt.piece_name[n]); free(pt.piece_abbreviation[n][WHITE]); free(pt.piece_notation[n]); free(pt.promotion_string[n]); free(pt.demotion_string[n]); pt.piece_move_flags[n] = move_flags; pt.piece_capture_flags[n] = capture_flags; pt.piece_flags[n] = piece_flags; pt.special_zone[WHITE][n] = bitboard_t::board_empty; pt.special_zone[BLACK][n] = bitboard_t::board_empty; pt.promotion_zone[WHITE][n] = promotion_zone[WHITE]; pt.promotion_zone[BLACK][n] = promotion_zone[BLACK]; pt.optional_promotion_zone[WHITE][n].clear(); pt.optional_promotion_zone[BLACK][n].clear(); pt.prison[WHITE][n] = bitboard_t::board_all; pt.prison[BLACK][n] = bitboard_t::board_all; pt.drop_zone[WHITE][n] = bitboard_t::board_all; pt.drop_zone[BLACK][n] = bitboard_t::board_all; pt.piece_name[n] = strdup(name); pt.piece_notation[n] = strdup(notation); pt.promotion_string[n] = strdup(promotion_string); pt.demotion_string[n] = NULL; pt.piece_value[n] = value; pt.demotion[n] = n; pt.piece_promotion_choice[n] = 0; pt.pzset[n] = false; pt.piece_drop_file_maximum[n] = 1; if (piece_flags & PF_ROYAL) { pt.piece_maximum[n][WHITE] = 1; pt.piece_maximum[n][BLACK] = 1; } else { pt.piece_maximum[n][WHITE] = 128; pt.piece_maximum[n][BLACK] = 128; } pt.piece_abbreviation[n][WHITE] = strdup(symbol); char *p = strchr(pt.piece_abbreviation[n][WHITE], ','); if (p) { p[0] = '\0'; p++; } else { p = pt.piece_abbreviation[n][WHITE] + strlen(pt.piece_abbreviation[n][WHITE]); } pt.piece_abbreviation[n][BLACK] = p; pt.num_piece_types++; piece_symbol_string[n ] = notation[0]; piece_symbol_string[n+1] = '\0'; piece_psymbol_string[n ] = notation[1]; piece_psymbol_string[n+1] = '\0'; piece_drop_string[n ] = toupper(pt.piece_abbreviation[n][WHITE][0]); piece_drop_string[n+1] = '\0'; return n; } bool add_special_move(const char *symbol, const bitboard_t *zone, move_flag_t move_flags) { int n; if (!symbol) return false; for (n=0; n zone, move_flag_t move_flags) { bitboard_t bz[2] = { zone, zone }; return add_special_move(symbol, bz, move_flags); } void set_maximum_number_of_kings(side_t side, int count) { for (int n=0; n bb = movegen.castle_mask[n][side]; bb.reset(square); assert(bb.onebit()); pt.castle_piece[side][n] = board.get_piece(bb.bitscan()); } board.clear(); } void deduce_castle_flags(side_t side, int king_from, int king_to, int rook_from) { movegen.deduce_castle_flags(side, king_from, king_to, rook_from); } void identify_promotion_options() { char buffer[3]; for (int n = 0; n. */ #ifndef PIECESTYPES_H #define PIECESTYPES_H #include #include #include "bitboard.h" #include "moveflag.h" #include "pieces.h" #include "eval_types.h" /* Piece flags */ #define PF_ROYAL 0x0001 /* Piece is royal */ #define PF_CASTLE 0x0002 /* Piece may castle */ #define PF_SET_EP 0x0004 /* Piece sets "en-passant" square when doing a special move */ #define PF_TAKE_EP 0x0008 /* Piece may capture en-passant */ #define PF_DROPNOCHECK 0x0010 /* Piece may not be dropped if it gives check */ #define PF_DROPNOMATE 0x0020 /* Piece may not be dropped if it gives mate */ #define PF_DROPONEFILE 0x0040 /* Piece may not be dropped if another piece of this type is on the same file */ #define PF_DROPDEAD 0x0080 /* Piece may be dropped where it has no moves */ #define PF_CANTMATE 0x0100 /* This piece, by itself, cannot mate */ #define PF_COLOURBOUND 0x0200 /* This piece is colour-bound */ #define PF_PAIRBONUS 0x0400 /* Piece gets a pair bonus for similar pieces on opposite colour */ #define PF_NORET 0x0800 /* Piece cannot return to its original position */ #define PF_NOMATE 0x1000 /* Piece may not give mate (it may give check) */ #define PF_SHAK 0x2000 #define PF_CAPTUREFLAG 0x4000 /* This piece is allowed to capture the flag */ struct value_comparator_t { int sort_value[256]; bool operator()(int a, int b) const { return sort_value[a] < sort_value[b]; } }; template struct piece_description_t { /* Define the properties of all piece types. * We don't use a struct for a piece type so that we can keep properties of different pieces more closely * packed, which is better for cache performance. * The index in the arrays here corresponds to the index in the board piece list. * * Basic entries: * move_flags (32 bits) * capture_flags (32 bits) * flags (32 bits) * name (string) * abbreviation (string) * notation (string) * For evaluation: * piece_value (16 bit) * centre_weight (8 bit) * advance_weight (8 bit) * shield_weight (8 bit) * mobility_score (8 bit) */ bitboard_t promotion_zone[NUM_SIDES][MAX_PIECE_TYPES]; bitboard_t optional_promotion_zone[NUM_SIDES][MAX_PIECE_TYPES]; bitboard_t special_zone[NUM_SIDES][MAX_PIECE_TYPES]; bitboard_t passer_mask[NUM_SIDES][8*sizeof(kind)]; bitboard_t weak_mask[NUM_SIDES][8*sizeof(kind)]; bitboard_t front_span[NUM_SIDES][8*sizeof(kind)]; bitboard_t prison[NUM_SIDES][MAX_PIECE_TYPES]; bitboard_t drop_zone[NUM_SIDES][MAX_PIECE_TYPES]; int num_piece_types; int pawn_steps[NUM_SIDES]; /* The number of moves a pawn has, a factor in pawn mobility and passer eval */ int8_t pawn_index[NUM_SIDES]; /* The piece type that will be evaluated as a pawn */ int8_t castle_piece[NUM_SIDES][NUM_CASTLE_MOVES];/* The piece type that will castle with the king, nominally "rook" */ move_flag_t piece_move_flags[MAX_PIECE_TYPES]; move_flag_t piece_capture_flags[MAX_PIECE_TYPES]; move_flag_t piece_special_move_flags[MAX_PIECE_TYPES]; piece_bit_t piece_promotion_choice[MAX_PIECE_TYPES]; uint16_t piece_flags[MAX_PIECE_TYPES]; int8_t demotion[MAX_PIECE_TYPES]; uint8_t piece_maximum[MAX_PIECE_TYPES][NUM_SIDES]; uint8_t piece_drop_file_maximum[MAX_PIECE_TYPES]; bool pieces_can_win[MAX_PIECE_TYPES][MAX_PIECE_TYPES]; int val_perm[MAX_PIECE_TYPES]; int16_t piece_value[MAX_PIECE_TYPES]; int16_t see_piece_value[MAX_PIECE_TYPES]; int16_t piece_promotion_value[MAX_PIECE_TYPES]; /* Piece classifications */ piece_bit_t royal_pieces; piece_bit_t defensive_pieces; piece_bit_t pawn_pieces; piece_bit_t minor_pieces; piece_bit_t major_pieces; piece_bit_t super_pieces; piece_bit_t shak_pieces; piece_bit_t deferral_allowed; eval_pair_t eval_value[MAX_PIECE_TYPES]; eval_pair_t eval_mobility[MAX_PIECE_TYPES][8*sizeof(kind)]; eval_pair_t eval_pair_bonus[MAX_PIECE_TYPES]; eval_pair_t eval_pst[MAX_PIECE_TYPES][8*sizeof(kind)]; int king_safety_weight[MAX_PIECE_TYPES]; int phase_weight[MAX_PIECE_TYPES]; int phase_scale; int avg_moves[MAX_PIECE_TYPES]; int max_moves[MAX_PIECE_TYPES]; int min_moves[MAX_PIECE_TYPES]; int8_t tropism[MAX_PIECE_TYPES][8*sizeof(kind)][8*sizeof(kind)]; int8_t mobility_score[MAX_PIECE_TYPES][8*sizeof(kind)]; char * piece_name[MAX_PIECE_TYPES]; char * piece_abbreviation[MAX_PIECE_TYPES][NUM_SIDES]; char * piece_notation[MAX_PIECE_TYPES]; char * promotion_string[MAX_PIECE_TYPES]; char * demotion_string[MAX_PIECE_TYPES]; bool pzset[MAX_PIECE_TYPES]; void sort_piece_values() { value_comparator_t compare; for (int n=0; n\n", min_moves[n], max_moves[n], avg_moves[n]); if (piece_flags[n] & PF_ROYAL) printf(" Royal\n"); if (piece_flags[n] & PF_PAIRBONUS) printf(" Pair bonus\n"); if (piece_flags[n] & PF_NORET) printf(" No return\n"); if (piece_flags[n] & PF_CANTMATE) printf(" Cannot deliver mate alone\n"); if (mate_helpers) { printf(" Can deliver mate with help of "); while (mate_helpers) { int n = bitscan32(mate_helpers); mate_helpers ^= (1<board.rule_flags & RF_KING_TRAPPED) // printf("Trapped kings\n"); //if (game->board.rule_flags & RF_KING_CORNERDRIVE) // printf("Kings can drive\n"); } }; #endif SjaakII/include/pieces.h000644 000765 000024 00000003700 12477662022 016143 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PIECES_H #define PIECES_H #include #include "moveflag.h" #define MAX_PIECE_TYPES 32 //16 #define PIECE_BITS 5 #define MAX_STEPPER_TYPES 16 #define MAX_LEAPER_TYPES 16 typedef uint32_t piece_bit_t; /* Bitfield colours */ typedef enum side_t { NONE=-1, WHITE, BLACK, NUM_SIDES } side_t; static const side_t next_side[NUM_SIDES] = { BLACK, WHITE }; /* Castle move options */ enum { SHORT, LONG, NUM_CASTLE_MOVES }; #ifdef __cplusplus inline side_t& operator++(side_t& side, int) { assert(side >= WHITE); assert(side <= BLACK); const int i = static_cast(side)+1; side = static_cast(i); return side; } #endif /* For the generalised description of moves, we need to pack the piece type and the colour bit into one bit * field. This feels a bit like a hack... */ static inline uint8_t piece_for_side(int piece, side_t side) { return piece | (side << PIECE_BITS); } static inline side_t side_for_piece(int piece) { #ifdef __cplusplus side_t side = static_cast((piece >> PIECE_BITS) & 0x01); return side; #else return (piece >> PIECE_BITS) & 0x01; #endif } static inline uint8_t neutral_piece(int piece) { return piece & ((1 << PIECE_BITS)-1); } #endif SjaakII/include/prefetch.h000644 000765 000024 00000000032 12452210627 016457 0ustar00eglebbkstaff000000 000000 #include "compilerdef.h" SjaakII/include/pst.h000644 000765 000024 00000001075 12433144250 015472 0ustar00eglebbkstaff000000 000000 #ifndef PST_H #define PST_H extern int psq_map[NUM_SIDES][128]; /* Base centralisation score for each square */ extern int centre_table[128]; /* Base advancement score for each square */ extern int advance_table[128]; /* Extra advancement score for proximity to promotion zone, for pawns */ extern int promo_table[128]; /* End game bonus for driving the defending king to the edge */ extern int lone_king_table[128]; /* Base shield score, for pawn shields */ extern int shield_table[128]; extern void initialise_base_evaluation_tables(int files, int ranks); #endif SjaakII/include/san.h000644 000765 000024 00000000220 12433144250 015434 0ustar00eglebbkstaff000000 000000 #include "move.h" #include "movelist.h" const char *move_to_short_string(move_t move, const movelist_t *movelist = NULL, char *buffer = NULL); SjaakII/include/score.h000644 000765 000024 00000001724 12433144250 016000 0ustar00eglebbkstaff000000 000000 #ifndef SCORE_H #define SCORE_H #define LEGALWIN 16000 #define LEGALLOSS (-LEGALWIN) #define LEGALDRAW 0 #define ILLEGAL (LEGALWIN+500) static inline bool is_mate_score(int score) { static const int mate = LEGALWIN - 1000; if ( score > mate || score < -mate ) return true; return false; } static inline int score_to_hashtable(int score, int depth) { if (is_mate_score(score)) { assert( (score>0 && score + depth <= LEGALWIN) || (score<0 && score - depth >= -LEGALWIN) ); if (score > 0) return score + depth; else return score - depth; } return score; } static inline int score_from_hashtable(int score, int depth) { if (is_mate_score(score)) { assert( (score>0 && (score - depth <= LEGALWIN)) || (score<0 && (score + depth >= -LEGALWIN)) ); if (score > 0) return score - depth; else return score + depth; } return score; } #endif SjaakII/include/search.h000644 000765 000024 00000123543 12502304433 016134 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "chase.h" #define iter if (output_iteration) output_iteration #define uci if (uci_output) uci_output #define xb if (xboard_output) xboard_output #define check_clock() \ {\ if (clock.max_nodes && (clock.nodes_searched >= clock.max_nodes)) abort_search |= 1;\ if (check_keyboard && check_keyboard(this)) abort_search |= 1;\ if (clock.check_clock && ((clock.nodes_searched & clock_nodes)==0))\ abort_search |= clock.check_clock(&clock);\ }(void)0 #include "mate.h" void dump_moves_since_root(void) { for (int n=clock.root_moves_played; n king = board.bbc[board.side_to_move] & board.royal; assert(!king.is_empty()); bitboard_t atk = movegen.get_all_attackers(&board, bitboard_t::board_all, king.bitscan()); for (int n=0; n king = board.bbc[board.side_to_move] & board.royal; assert(!king.is_empty()); bitboard_t atk = movegen.get_all_attackers(&board, bitboard_t::board_all, king.bitscan()); for (int n=0; n flag = board.flag[side]; bitboard_t bb = flag & board.bbc[side]; if (bb.is_empty()) return false;; /* Filter out pieces that are not allowed to capture the flag */ for (int n=0; n flag = board.flag[side]; bitboard_t bb = flag & board.bbc[side]; if (bb.is_empty()) continue; /* Filter out pieces that are not allowed to capture the flag */ for (int n=0; n=0; n-=2) { if ((board.rule_flags & RF_USE_CAPTURE) == 0 && is_irreversible_move(move_list[n+1])) return count; if ((board.rule_flags & RF_USE_CAPTURE) == 0 && is_irreversible_move(move_list[n])) return count; count += (ui[n].hash == board.hash); } return count; } inline bool position_repeated() { int rep_in_game = 0; int count = 0; if (repetition_hash_table[board.hash&0xFFFF]>=2) { int n; for (n=(int)moves_played-2; n>=0; n-=2) { if ((board.rule_flags & RF_USE_CAPTURE) == 0 && is_irreversible_move(move_list[n])) break; if ((board.rule_flags & RF_USE_CAPTURE) == 0 && is_irreversible_move(move_list[n+1])) break; if (ui[n].hash == board.hash) { count++; rep_in_game += (n <= clock.root_moves_played); } } } return count && count >= rep_in_game; } inline bool board_position_repeated_loss() { if (board_repetition_hash_table[board.board_hash&0xFFFF]>=2) { const side_t me = board.side_to_move; bool pure_loss = true; bool pure_gain = true; int8_t holdings[MAX_PIECE_TYPES][NUM_SIDES]; memset(holdings, 0, sizeof holdings); for (int n=(int)moves_played-1; n>=0; n--) { move_t move = move_list[n]; if ((board.rule_flags & RF_USE_CAPTURE) == 0 && is_irreversible_move(move)) break; if (get_move_holdings(move)) { uint16_t p = get_move_holding(move); int count = decode_holding_count(p); int piece = decode_holding_piece(p); side_t side = decode_holding_side(p); holdings[piece][side] += count; } if (ui[n].board_hash == board.board_hash && ui[n].hash != board.hash) { for (int piece = 0; piece 0) pure_loss = false; } if (pure_gain) return false; return pure_loss; } } } return false; } inline bool material_draw() { if (board.rule_flags & RF_CAPTURE_THE_FLAG) return false; if (lone_king(WHITE) && lone_king(BLACK)) return true; /* TODO */ return false; } inline bool lone_king(side_t side) { return (board.royal & board.bbc[side]) == board.bbc[side] && board.bbc[side].onebit(); } inline bool zugzwang_threat() { for (side_t side = WHITE; side < NUM_SIDES; side++) { /* If one side has a lone king, there is a zugzwang threat */ if (lone_king(side)) return true; } int tempo_movers = 0; /* If the side to move only has pieces that cannot make a tempo move, * ditto. * FIXME: currently, we only detect the presence of pieces that cannot * return. The correct zugzwang threat detection needs to know if a * piece can return to its original square in an odd number of steps. */ for (int n=0; nnum_piece_types; n++) { if (!(board.bbc[board.side_to_move] & board.bbp[n]).is_empty()) { if (!(board.piece_types->piece_flags[n] & PF_NORET)) tempo_movers++; } } return tempo_movers <= 1; } bool is_pawn_push(move_t move, side_t side) { if (pt.pawn_pieces & (1 << get_move_piece(move))) { if (bitboard_t::board_homeland[next_side[side]].test(get_move_from(move))) return true; } return false; } bool is_recapture_move(move_t move, move_t prev_move) { return is_capture_move(move) && is_capture_move(prev_move) && get_move_to(move) == get_move_to(prev_move); } void score_moves(int depth, move_t hash_move, move_t prev_move, move_t threat_move) { const side_t me = board.side_to_move; for (int n = 0; n 2 && is_killer(depth-2, move)) { movelist[depth].score[n] += 900; if (move == killer[depth-2][0]) movelist[depth].score[n] += 50; } else if (is_killer(depth+2, move)) { movelist[depth].score[n] += 800; if (move == killer[depth+2][0]) movelist[depth].score[n] += 50; } else if (is_counter(depth, prev_move, move)) { movelist[depth].score[n] += 1500; } else if (is_castle_move(move)) { movelist[depth].score[n] += 600; } else if (is_capture_move(move)) { int s = see(move); if (s > 0) movelist[depth].score[n] += 2400 + s / 10; else movelist[depth].score[n] += s; if (threat_move && get_move_to(move) == get_move_from(threat_move) && s < 0) movelist[depth].score[n] += 1000; } else if (is_pickup_move(move)) { if (threat_move && get_move_to(threat_move) == get_move_from(move)) { movelist[depth].score[n] += 1500; } else { movelist[depth].score[n] += 0; } } else if (is_drop_move(move)) { int history_score = get_move_history_score(move); int history_scale = get_move_history_scale(move); int s = see(move); if (s > 0) { int h = history_scale ? 100 * history_score / history_scale : 100; if (!(board.bbc[me] & board.royal & bitboard_t::neighbour_board[get_move_to(move)]).is_empty()) movelist[depth].score[n] += 1200 + h; else if (bitboard_t::board_homeland[next_side[me]].test(get_move_to(move))) movelist[depth].score[n] += 1100 + h; movelist[depth].score[n] += s / 10; } else { int h = history_scale ? 500 * history_score / history_scale : 500; movelist[depth].score[n] += s + h; } } else if (max_history && !board.check() && !is_promotion_move(move) && !is_capture_move(move)) { int history_score = get_move_history_score(move); int history_scale = get_move_history_scale(move); if (history_scale) { int s = 500 * history_score / history_scale; if (s) { movelist[depth].score[n] = 0 + s; } else { s = see(move); movelist[depth].score[n] += s; } } if (threat_move && get_move_from(move) == get_move_to(threat_move)) movelist[depth].score[n] += 500; } else { int s = see(move); movelist[depth].score[n] += s; if (threat_move && get_move_from(move) == get_move_to(threat_move)) movelist[depth].score[n] += 500; } if (is_gate_move(move)) movelist[depth].score[n] += 200; if (depth < 3 && clock.root_moves_played < 10 && random_ok) { movelist[depth].score[n] += genrandui() & 0xff; } } } int qsearch(int alpha, int beta, int draft, int depth) { int score = -LEGALWIN; side_t me = board.side_to_move; truncate_principle_variation(depth); /* Check whether our search time for this move has expired */ check_clock(); if (abort_search) return 0; if (!board.check() && (board.rule_flags & RF_FORCE_CAPTURE) && (draft < -2)) { return static_qsearch(beta, depth+1); } if ((board.rule_flags & RF_ALLOW_PICKUP) && (draft < -2)) return static_qsearch(beta, depth+1); if (depth >= MAX_TOTAL_DEPTH) return static_qsearch(beta, depth+1); int static_score = 0; if (!board.check()) { static_score = static_evaluation(me, alpha, beta); /* Stand-pat cut-off */ if (static_score >= beta) return static_score; if (static_score > alpha) alpha = static_score; } /* Generate moves */ movelist[depth].clear(); movegen.generate_moves(&movelist[depth], &board, me, true, pt.deferral_allowed); if (movelist[depth].num_moves == 0) return static_score; /* Store the previous move: this is used to change move ordering on this * move. If there is no previous move, then this move will be null. */ assert(moves_played > 0); move_t prev_move = move_list[moves_played-1]; /* Score and sort the moves */ for (int n = 0; n best_score) { best_score2 = best_score; best_score = score; } if (score > alpha) { /* New best line */ alpha = score; backup_principle_variation(depth, move); } } if (board.rule_flags & RF_ALLOW_PICKUP) best_score = best_score2; if (best_score == -LEGALWIN) best_score = static_score; if (board.check() && legal_moves == 0) { best_score = (mate_score + depth); move_t prev_move = move_list[moves_played-1]; /* Make sure mate wasn't caused by an illegal drop */ if (board.check() && is_drop_move(prev_move)) { int p = get_move_piece(prev_move); if (pt.piece_flags[p] & PF_DROPNOMATE) return ILLEGAL; } /* Test if the mate is legal, that is to say: * - The checking piece is allowed to deliver mate * - The mate follows a sequence of checks at least one of which * makes the mate OK (is classified as "shak"). * The first is illegal, the second is only a draw. */ if (board.check()) { if (!is_valid_mate()) return ILLEGAL; if (board.rule_flags & RF_USE_SHAKMATE) { if (!board.have_shak()) best_score = 0; } } /* Verify that all moves during QS were check moves, so we know that * all evasions were examined. */ int c = 2; for (int n=draft+2; n<=0; n+=2) { if ((ui[moves_played-c].board_flags & BF_CHECK) == 0) best_score = static_score; c+=2; } } return best_score; } /* Idea taken from Senpai */ int static_qsearch(int beta, int depth) { int static_score = static_evaluation(board.side_to_move); int best_score = static_score; if (static_score >= beta) return static_score; movelist[depth].clear(); movegen.generate_moves(&movelist[depth], &board, board.side_to_move, true, pt.deferral_allowed); bitboard_t cdone; for (int n=0; n 0) value += pt.piece_value[get_move_promotion_piece(move)] - pt.piece_value[get_move_piece(move)]; int score = static_score + value; if (score > best_score) { best_score = score; if (best_score >= beta) break; } } return best_score; } int get_extension(move_t /* move */, int move_score) { /* Check extension: only for safe checks. * TODO: exempt dicovered checks */ return board.check() && move_score >= 0;//see(move) >= 0; } int get_reduction(move_t move, int move_score, int /* move_count */, int draft) { int r = 0; if (move_score > 1500) return 0; r = 1; if (is_drop_move(move) && move_score < 1000) r++; if (is_pickup_move(move) && move_score < 1000) r++; if (r && draft > 4) r += draft / 4; return r; } int search(int alpha, int beta, int draft, int depth) { assert(beta > alpha); assert(depth >= 0); int best_score = -LEGALWIN; int score = -LEGALWIN; int moves_searched = 0; const side_t me = board.side_to_move; move_t prev_move = 0; move_t move = 0; truncate_principle_variation(depth); /* Check whether our search time for this move has expired */ check_clock(); if (abort_search) return 0; /* Check whether we're looking for a checkmate. * If so, prune branches that are worse than the best mate found so far * (mate distance pruning). */ alpha = std::max(alpha, -LEGALWIN + depth); beta = std::min(beta, LEGALWIN - depth - 1); if (alpha >= beta) return alpha; assert(alpha >= -LEGALWIN); assert(beta <= LEGALWIN); if (flags_are_captured()) return flag_score + depth; /* We still need to return a move at the root, even if the * heuristic says the current position is a repetition draw! * If it were, we would not get here. */ if (depth > 0) { if (board.fifty_counter >= 101) { if (!board.check()) /* defer the 50-move claim when in check, in case it's mate */ return LEGALDRAW; } if (position_repeated()) { if (board.rule_flags & RF_USE_CHASERULE) { if (depth > 1) switch (test_chase()) { case NO_CHASE: break; case DRAW_CHASE: return LEGALDRAW; case WIN_CHASE: if (beta == alpha+1) return ILLEGAL; break; case LOSE_CHASE: return -ILLEGAL; break; } } else { if (board.check()) { if (perpetual == LEGALDRAW) return -perpetual; if (perpetual == -ILLEGAL) return -perpetual; return -(perpetual + depth); } if (rep_score == LEGALDRAW) return rep_score; /* Allow check evasions to repeat */ if (rep_score == -ILLEGAL) { if ((ui[moves_played-1].board_flags & BF_CHECK) == 0) /* HACK: allow check evasion */ return -rep_score; } else { return -(rep_score + depth); } } } else if ((board.rule_flags & RF_USE_CAPTURE) && board_position_repeated_loss() && depth) { return alpha-1; } if (material_draw()) return LEGALDRAW; if (board.rule_flags & RF_USE_BARERULE) { if (lone_king(next_side[me])) { /* We know that not both sides have a bare king (otherwise it * would already have been declared a legal draw) and it is our * turn, so if the enemy could have captured our last piece he * clearly failed to do so - in other words, we have won. */ return -bare_king_score; } } } //if ( (depth == 0 || depth == 1 || draft > 8 || is_mate_score(beta)) && (board.rule_flags & RF_USE_DROPS)) { bool mate_search = (depth == 1) || (depth == 0 && best_move[0] != 0) || (draft > 8); if ( mate_search && ((option_ms >= MATE_SEARCH_ENABLED) || ((board.rule_flags & RF_USE_DROPS) && option_ms >= MATE_SEARCH_ENABLE_DROP)) ) { int xply = (depth < 2) ? draft / 4 : 0; int mply = (depth == 0 && best_move[0] == 0) ? 1 : (3 + 2*xply); int score = msearch(alpha, beta, mply, depth); if (is_mate_score(score)) return score; } if (draft <= 0 || depth > MAX_SEARCH_DEPTH) return qsearch(alpha, beta, 0, depth); /* Test for transposition table cut-offs */ int hash_depth, hash_score; unsigned int hash_flag; move_t hash_move = 0; bool have_hash = retrieve_table(transposition_table, board.hash, &hash_depth, &hash_score, &hash_flag, &hash_move); bool hash_ok = hash_depth >= draft || is_mate_score(hash_score); if (have_hash && hash_ok && board.fifty_counter < 80 && depth > 0) { hash_score = score_from_hashtable(hash_score, depth); //positions_in_hashtable++; //bool exact_ok = (depth > 1) || (beta == alpha+1); bool exact_ok = (beta == alpha+1); // FIXME: use crafty-like PV table if ((hash_flag & HASH_TYPE_EXACT) && exact_ok) { if (hash_score > alpha) backup_principle_variation(depth, hash_move); return hash_score; } else if ((hash_flag & (HASH_TYPE_UPPER|HASH_TYPE_EXACT)) && (hash_score<=alpha)) { return hash_score; } else if ((hash_flag & (HASH_TYPE_LOWER|HASH_TYPE_EXACT)) && (hash_score>=beta)) { return hash_score; } } /* Store the previous move: this is used to change move ordering on this * move. If there is no previous move, then this move will be null. */ if (moves_played > 0) prev_move = move_list[moves_played-1]; /* Pre-conditions for particular pruning options. */ bool razor = draft <= 3 && !is_mate_score(beta) && !board.check(); bool avoid_null = beta > alpha+1 || board.check() || prev_move == 0 || zugzwang_threat() || is_mate_score(beta); /* Calculate static evaluation if needed */ bool need_static = razor || !avoid_null; int static_score = 0; if (need_static) { static_score = static_evaluation(me, alpha, beta); avoid_null = avoid_null || static_score < beta; } /* Razoring */ if (razor) { assert(need_static); int score = static_score - draft * draft * 50; if (score >= beta) return score; } /* Null-move */ move_t threat_move = 0; if (!avoid_null) { assert(need_static); assert(!player_in_check(me)); int r = 2; int score; playmove(0); clock.nodes_searched++; if (draft - r < 1) score = -static_qsearch(-(beta-1), depth+1); else score = -search(-beta, -(beta-1), draft - 1 -r, depth+1); takeback(); if (score >= beta && !is_mate_score(score) && !abort_search) {// && draft >= 3) { if (abs(score) < LEGALWIN) store_table_entry(transposition_table, board.hash, draft - 1 - r, score_to_hashtable(score, depth), HASH_TYPE_LOWER, 0); return score; } threat_move = best_move[depth+1]; if (!is_capture_move(threat_move) && !is_mate_score(score)) threat_move = 0; } /* Internal iterative deepening */ if (hash_move == 0 && beta>alpha+1 && draft > 3) { int score = search(alpha, beta, draft-2, depth); if (score > alpha) hash_move = best_move[depth]; } /* Generate all moves */ movelist[depth].clear(); movegen.generate_moves(&movelist[depth], &board, me, false, pt.deferral_allowed); int legal_moves = movelist[depth].num_moves; /* No moves generated at all? */ if (legal_moves == 0) goto no_moves; /* Score and sort the moves */ score_moves(depth, hash_move, prev_move, threat_move); /* Search the first move */ hash_flag = HASH_TYPE_UPPER; while ((move = movelist[depth].next_move())) { int move_score = movelist[depth].get_move_score(); playmove(move); if (player_in_check(me)) { /* Illegal move */ legal_moves--; takeback(); continue; } clock.nodes_searched++; board.check(movegen.was_checking_move(&board, board.side_to_move, move)); if ((board.rule_flags & RF_USE_SHAKMATE) && board.check()) test_shak(); int e = get_extension(move, move_score); score = -search(-beta, -alpha, draft-1 + e, depth+1); if (score < LEGALLOSS) { /* Illegal move, but requires search to identify */ legal_moves--; takeback(); continue; } if (score > alpha && !abort_search) { /* New best line found */ hash_flag = HASH_TYPE_EXACT; alpha = score; backup_principle_variation(depth, move); } takeback(); moves_searched++; break; } /* Search all other moves, until we find a cut-off */ best_score = score; hash_move = move; while (alpha < beta && (move = movelist[depth].next_move())) { bool in_check = board.check(); int move_score = movelist[depth].get_move_score(); /* Prune unsafe drops near the tips */ if (is_drop_move(move)) { if (draft < 3 && move_score < 500 && !in_check) continue; //if (draft < 2 && !in_check && !is_mate_score(beta)) continue; if (depth == 0 && draft == 1 && moves_searched) continue; } if (draft < 3 && is_pickup_move(move)) continue; playmove(move); if (player_in_check(me)) { legal_moves--; takeback(); continue; } board.check(movegen.was_checking_move(&board, board.side_to_move, move)); if ((board.rule_flags & RF_USE_SHAKMATE) && board.check()) test_shak(); clock.nodes_searched++; /* Futility pruning of drop moves in frontier nodes */ if (draft == 1 && is_drop_move(move) && !in_check && !board.check()) { takeback(); continue; } bool avoid_reduction = in_check || board.check() || is_capture_move(move) || is_promotion_move(move) || is_castle_move(move) || is_pawn_push(move, me); int e = get_extension(move, move_score); int r = (e || avoid_reduction) ? 0 : get_reduction(move, move_score, moves_searched, draft); if (depth < 2) { score = -search(-beta, -alpha, draft-1 + e-r, depth+1); if (score > alpha && score < beta && r) score = -search(-beta, -alpha, draft-1 + e, depth+1); } else { score = -search(-(alpha+1), -alpha, draft-1 + e-r, depth+1); if (score < LEGALLOSS) { /* Illegal move, but requires search to identify */ legal_moves--; takeback(); continue; } if (score > alpha && ((beta > alpha+1) || r)) score = -search(-beta, -alpha, draft-1 + e, depth+1); } takeback(); moves_searched++; if (abort_search) return 0; if (score > best_score) { best_score = score; if (score > alpha) { /* New best line */ hash_flag = HASH_TYPE_EXACT; alpha = score; hash_move = move; backup_principle_variation(depth, move); } } } if (alpha >= beta) { /* Beta cutoff */ /* Store good moves in the killer slots, but only if: * - we were not in check at the beginning of this move * - the move is not a promotion (already high in the list) * - the move was not a capture (already high in the list) */ store_killer(hash_move, depth); store_mate_killer(hash_move, depth, best_score); store_counter_move(depth, prev_move, hash_move); update_history(move, draft * draft); if (prev_move == 0) store_null_killer(depth, hash_move); hash_flag = HASH_TYPE_LOWER; branches_pruned++; /* Update history for all other moves that have failed to produce a * cut-off, rather than doing this for all moves that do not improve * alpha. * Doing this here avoids polluting the history tables in ALL-nodes. */ for (int n=0; n 0); hash_flag = HASH_TYPE_EXACT; hash_move = 0; best_score = board.check() ? (mate_score + depth) : (stale_score + depth); /* Make sure mate wasn't caused by an illegal drop */ if (board.check() && is_drop_move(prev_move)) { int p = get_move_piece(prev_move); if (pt.piece_flags[p] & PF_DROPNOMATE) return ILLEGAL; } if (board.bbc[board.side_to_move].is_empty()) best_score = no_piece_score + depth; if (best_score == depth) hash_flag = HASH_TYPE_UPPER; /* Test if the mate is legal, that is to say: * - The checking piece is allowed to deliver mate * - The mate follows a sequence of checks at least one of which * makes the mate OK (is classified as "shak"). * The first is illegal, the second is only a draw. */ if (board.check()) { if (!is_valid_mate()) return ILLEGAL; if (board.rule_flags & RF_USE_SHAKMATE) { if (!board.have_shak()) best_score = 0; } } } assert(best_score > -LEGALWIN || legal_moves == 0); assert(hash_move || legal_moves == 0); best_move[depth] = hash_move; /* store evaluation in the transposition table */ //if (hash_flag & HASH_TYPE_UPPER) // hash_move = max_nodes_move; if (legal_moves) store_table_entry(transposition_table, board.hash, draft, score_to_hashtable(best_score, depth), hash_flag, hash_move); return best_score; } void print_principle_variation(int d = 0) { int c; int root_move_number = start_move_count; if (board.side_to_move) { root_move_number += 1; iter(" %d. ...", (int)(root_move_number+moves_played)/2+1); } for (c=0; c LEGALWIN) depth = LEGALWIN - score; for (int c=0; c= 101) return SEARCH_GAME_ENDED_50_MOVE; if (count_repetition() >= repeat_claim && !(board.rule_flags & RF_USE_CHASERULE)) return SEARCH_GAME_ENDED_REPEAT; if (flags_are_captured()) return SEARCH_GAME_ENDED_FLAG_CAPTURED; if (material_draw()) return SEARCH_GAME_ENDED_INSUFFICIENT; generate_legal_moves(movelist); /* No legal moves? */ if (movelist->num_moves == 0) { if (board.bbc[board.side_to_move].is_empty()) return SEARCH_GAME_ENDED_NOPIECES; if (!board.check()) return SEARCH_GAME_ENDED_STALEMATE; /* Make sure mate wasn't caused by an illegal drop or a piece that is * not allowed to deliver mate. */ if (moves_played) { move_t prev_move = move_list[moves_played-1]; int p = get_move_piece(prev_move); if (is_drop_move(prev_move)) { if (pt.piece_flags[p] & PF_DROPNOMATE) return SEARCH_GAME_ENDED_FORFEIT; } if (!is_valid_mate()) return SEARCH_GAME_ENDED_FORFEIT; } /* Test if the mate is legal, that is to say: * - The checking piece is allowed to deliver mate * - The mate follows a sequence of checks at least one of which * makes the mate OK (is classified as "shak"). * The first is illegal, the second is only a draw. */ if (board.rule_flags & RF_USE_SHAKMATE) if (!board.have_shak()) return SEARCH_GAME_ENDED_INADEQUATEMATE; return SEARCH_GAME_ENDED_MATE; } if (board.rule_flags & RF_USE_BARERULE) { side_t other = next_side[board.side_to_move]; if (lone_king(board.side_to_move)) { /* Can we capture the last piece? */ if ((board.bbc[other] & ~board.royal).onebit()) { for (int n = 0; nnum_moves; n++) { if (is_capture_move(movelist->move[n])) return SEARCH_OK; } /* Apparently not - we've lost! */ return SEARCH_GAME_ENDED_LOSEBARE; } } if (lone_king(other)) return SEARCH_GAME_ENDED_WINBARE; } return SEARCH_OK; } play_state_t think(int max_depth) { play_state_t state; uint64_t start_time; bool mate_search = false; movelist_t movelist; int depth; clock.extra_time = 0; clock.root_moves_played = (int)moves_played; clock.nodes_searched = 0; branches_pruned = 0; abort_search = false; /* Start the clock */ start_time = get_timer(); start_clock(&clock); /* Test if the game has ended */ state = get_game_end_state(&movelist); if (!repetition_claim && state == SEARCH_GAME_ENDED_REPEAT) state = SEARCH_OK; if (state != SEARCH_OK) return state; for (side_t side = WHITE; side<=BLACK; side++) if ((board.bbc[side] & ~board.royal).is_empty()) mate_search = true; /* Prepare the transpostion table for a new search iteration: * Resets the write count and increases the generation counter. */ prepare_hashtable_search(transposition_table); int hash_depth, hash_score; uint32_t hash_flag; retrieve_table(transposition_table, board.hash, &hash_depth, &hash_score, &hash_flag, &best_move[0]); /* Iterative deepening loop */ int e = board.check(); clock.extra_time = clock.time_left; best_move[0] = 0; int score = search(-LEGALWIN, LEGALWIN, 1, 0); clock.extra_time = 0; if (abort_search) { xb("# Aborted ply 1 search - no move!\n"); if (best_move[0] == 0) { xb("# Pick random move\n"); best_move[0] = movelist.move[0]; } length_of_variation[0] = 1; principle_variation[0][0] = best_move[0]; xb("% 3d % 5d %6d %9d ", 1, score, (int)(get_timer()-start_time)/10000, (int)clock.nodes_searched); print_principle_variation_xb(&movelist); xb("\n"); } move_t move = best_move[0]; if (!abort_search) for (depth=2; depth<=max_depth; depth++) { scale_history(); movelist.rewind(); for (int window = 10; window < 2*LEGALWIN; window *= 2) { if (depth <= 2) window = LEGALWIN / (depth - 1); if (mate_search && !is_mate_score(score)) window = LEGALWIN; int alpha = std::max(score - window, -LEGALWIN); int beta = std::min(score + window, LEGALWIN); int new_score = search(alpha, beta, depth + e, 0); clock.extra_time = 0; if (abort_search) break; score = new_score; if (score > alpha && score < beta) { move = best_move[0]; break; } /* Report a fail-low */ if (score < alpha && move) { move_t move = best_move[0]; if (show_fail_low) { iter("% 3d. %6.2f %9d %+2.2f ", depth, (get_timer()-start_time)/1000000.0, (int)clock.nodes_searched, score/100.0); iter(" %d.", (int)(start_move_count + moves_played)/2+1); if (board.side_to_move) iter(" ..."); iter(" %s?", move_to_short_string(move, &movelist)); iter("\n"); xb("% 3d % 5d %6d %9d ", depth, score, (int)(get_timer()-start_time)/10000, (int)clock.nodes_searched); xb(" %d.", (int)(start_move_count + moves_played)/2+1); if (board.side_to_move) xb(" ..."); xb(" %s?", move_to_short_string(move, &movelist)); xb("\n"); } clock.extra_time = (9*clock.time_left)/10; } /* Report a fail-high */ if (score >= beta) { move = best_move[0]; if (show_fail_high) { iter("% 3d. %6.2f %9d %+2.2f ", depth, (get_timer()-start_time)/1000000.0, (int)clock.nodes_searched, score/100.0); iter(" %d.", (int)(start_move_count + moves_played)/2+1); if (board.side_to_move) iter(" ..."); iter(" %s!", move_to_short_string(move, &movelist)); iter("\n"); xb("% 3d % 5d %6d %9d ", depth, score, (int)(get_timer()-start_time)/10000, (int)clock.nodes_searched); xb(" %d.", (int)(start_move_count + moves_played)/2+1); if (board.side_to_move) xb(" ..."); xb(" %s!", move_to_short_string(move, &movelist)); xb("\n"); } clock.extra_time = (5*clock.time_left)/10; } } iter("% 3d. %6.2f %9d %+2.2f ", depth, (get_timer() - start_time)/1000000.0, (int)clock.nodes_searched, score/100.0); print_principle_variation(); iter("\n"); xb("% 3d % 5d %6d %9d ", depth, score, (int)(get_timer()-start_time)/10000, (int)clock.nodes_searched); print_principle_variation_xb(&movelist); xb("\n"); uci("info depth %d score cp %d nodes %llu time %llu hashfull %d pv", depth, score, (unsigned long long)clock.nodes_searched, (unsigned long long)peek_timer(&clock), (int)std::min(1000, (int)(transposition_table->write_count*1000/transposition_table->number_of_elements))); print_principle_variation_uci(); uci("\n"); store_principle_variation(score, depth); if (is_mate_score(score) && (LEGALWIN - abs(score)) == length_of_variation[0] && move && !analysing) break; if (abort_search) break; if (movelist.num_moves == 1 && move && !pondering && !analysing) break; /* Check if we have enough time for the next iteration, assuming an * effective branching ratio of 2. */ if ( clock.check_clock && peek_timer(&clock) > get_chess_clock_time_for_move(&clock)/2 && move) break; } while (analysing && !abort_search) check_clock(); if (score < resign_threshold) resign_count++; else resign_count = 0; if (abs(score) < draw_threshold) draw_count++; else draw_count = 0; if (moves_played > 400) draw_count += 50; //printf("# %d [draw %d / %d] [resign %d / %d]\n", score, draw_threshold, draw_count, resign_threshold, resign_count); assert(move); playmove(move); ponder_move = 0; if (length_of_variation[0] > 2) ponder_move = principle_variation[1][0]; return SEARCH_OK; } bool ponder() { move_t ponder_move = this->ponder_move; /* Verify that the ponder move is legal. * There is a corner-case where the ponder move is illegal if the game * was terminated by 50-move or three-fold repetition. * There may be a more elegant way to resolve this, but this works. */ movelist_t movelist; generate_legal_moves(&movelist); pondering = false; for (int n = 0; nponder_move = ponder_move; return true; } bool analyse() { move_t ponder_move = this->ponder_move; if (analyse_move) return false; analyse_move = 0; generate_legal_moves(&analyse_movelist); /* Search the current position */ abort_search = false; while (analysing && !abort_search) { if (think(MAX_SEARCH_DEPTH) == SEARCH_OK) takeback(); else { while (analysing && !abort_search) check_clock(); } } if (analyse_move) playmove(analyse_move); analyse_move = 0; this->ponder_move = ponder_move; return true; } #undef iter #undef uci #undef xb #undef check_clock SjaakII/include/see.h000644 000765 000024 00000012602 12502304433 015434 0ustar00eglebbkstaff000000 000000 int move_mvvlva(move_t move) const { int value = 0; if (is_capture_move(move)) { value += pt.see_piece_value[board.get_piece(get_move_capture_square(move))] * 8; value -= pt.see_piece_value[get_move_piece(move)] / 8; } return value; } int move_value(move_t move, side_t /* side_to_move */) const { /* Capture a piece */ int value = 0; if (is_capture_move(move)) value += pt.see_piece_value[board.get_piece(get_move_capture_square(move))]; if (is_drop_move(move)) value += pt.see_piece_value[get_move_piece(move)]; if (is_promotion_move(move)) { //value += pt.see_piece_value[get_move_promotion_piece(move)]; //value -= pt.see_piece_value[get_move_piece(move)]; } /* TODO: gate moves have an extra drop */ return value; } struct { move_t move; uint32_t lock; int score; } see_cache[0xFFFF + 1 + 8]; bool probe_see_cache(move_t move, int *score) { int index = board.hash & 0xFFFF; uint32_t key = board.hash >> 32; for (int n = 0; n<8; n++) { if (see_cache[index + n].lock == key && see_cache[index + n].move == move) { *score = see_cache[index + n].score; return true; } } return false; } void store_see_cache(move_t move, int score) { int index = board.hash & 0xFFFF; uint32_t key = board.hash >> 32; uint32_t okey = key; move_t omove = move; int oscore = score; for (int n = 0; n<8; n++) { uint32_t new_key = see_cache[index + n].lock; move_t new_move = see_cache[index + n].move; int new_score = see_cache[index + n].score; see_cache[index+n].lock = okey; see_cache[index+n].move = omove; see_cache[index+n].score = oscore; if (new_key == key && new_move == move) return; okey = new_key; omove = new_move; oscore = new_score; } } /* Perform static exchange evaluation for a given capture move. * Uses the "swap" algorithm * (http://chessprogramming.wikispaces.com/SEE+-+The+Swap+Algorithm). * returns the evaluation in centipawns. * The move doesn't need to be a capture; if it isn't then this function * can be used to find out if it puts a piece "en-prise" */ int see(move_t move) { int score[128]; int depth; side_t side = board.side_to_move; int piece = get_move_piece(move); int square = get_move_to(move); int from = get_move_from(move); int last_piece = piece; bitboard_t attackers, hidden_attackers, pinned; bitboard_t xray_update; bitboard_t own; bitboard_t mask = bitboard_t::board_all; /* Test if this position/move was calculated before and re-use */ if (probe_see_cache(move, &depth)) return depth; /* Initial gain: the piece on the target square */ depth = 0; score[depth] = move_value(move, board.side_to_move); if (is_capture_move(move)) { /* Easy: if the piece we use to capture the enemy piece is worth less * than the piece we captured, it's always a winning capture, so return a * rough estimate for the SEE score. */ if (score[depth] > pt.piece_value[piece]) return score[depth] - pt.piece_value[piece]/2; /* Perform the capture on the board. * In this case we need to explicitly clear the capture square because * the first move might be an en-passant capture. */ mask.reset(get_move_capture_square(move)); } /* We need to update the list of attackers if the moving piece is a * slider or moves along a ray. This includes some types of leaper, but * that is currently NOT taken into account. * *TODO* */ for (int n = 0; n. */ #ifdef __cplusplus extern "C" { #endif double myexp(double x); #ifdef __cplusplus } #endif SjaakII/include/squares.h000644 000765 000024 00000001600 12465213742 016351 0ustar00eglebbkstaff000000 000000 #ifndef SQUARE_H #define SQUARE_H #include extern char *square_names[128]; extern char *file_names[16]; extern char *rank_names[16]; extern int rank_offset; extern uint8_t packed_file_rank[128]; extern const char *kingside_castle; extern const char *queenside_castle; extern int div_file; extern bool keep_labels; void initialise_square_names(int files, int ranks); void relabel_shogi_square_names(void); void relabel_chess_square_names(void); int square_from_string(const char *str); /******************************************************************** * Functions for dealing with packing/unpacking square rows/files * ********************************************************************/ static inline int unpack_rank(int packed) { return packed_file_rank[packed] >> 4; } static inline int unpack_file(int packed) { return packed_file_rank[packed] & 0xf; } #endif SjaakII/include/test_suite.h000644 000765 000024 00000624664 12470157255 017105 0ustar00eglebbkstaff000000 000000 static const char *wac_test[] = { "2rr3k/pp3pp1/1nnqbN1p/3pN3/2pP4/2P3Q1/PPB4P/R4RK1 w - - bm Qg6; id \"WAC.001\";", "8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - bm Rxb2; id \"WAC.002\";", "5rk1/1ppb3p/p1pb4/6q1/3P1p1r/2P1R2P/PP1BQ1P1/5RKN w - - bm Rg3; id \"WAC.003\";", "r1bq2rk/pp3pbp/2p1p1pQ/7P/3P4/2PB1N2/PP3PPR/2KR4 w - - bm Qxh7+; id \"WAC.004\";", "5k2/6pp/p1qN4/1p1p4/3P4/2PKP2Q/PP3r2/3R4 b - - bm Qc4+; id \"WAC.005\";", "7k/p7/1R5K/6r1/6p1/6P1/8/8 w - - bm Rb7; id \"WAC.006\";", "rnbqkb1r/pppp1ppp/8/4P3/6n1/7P/PPPNPPP1/R1BQKBNR b KQkq - bm Ne3; id \"WAC.007\";", "r4q1k/p2bR1rp/2p2Q1N/5p2/5p2/2P5/PP3PPP/R5K1 w - - bm Rf7; id \"WAC.008\";", "3q1rk1/p4pp1/2pb3p/3p4/6Pr/1PNQ4/P1PB1PP1/4RRK1 b - - bm Bh2+; id \"WAC.009\";", "2br2k1/2q3rn/p2NppQ1/2p1P3/Pp5R/4P3/1P3PPP/3R2K1 w - - bm Rxh7; id \"WAC.010\";", "r1b1kb1r/3q1ppp/pBp1pn2/8/Np3P2/5B2/PPP3PP/R2Q1RK1 w kq - bm Bxc6; id \"WAC.011\";", "4k1r1/2p3r1/1pR1p3/3pP2p/3P2qP/P4N2/1PQ4P/5R1K b - - bm Qxf3+; id \"WAC.012\";", "5rk1/pp4p1/2n1p2p/2Npq3/2p5/6P1/P3P1BP/R4Q1K w - - bm Qxf8+; id \"WAC.013\";", "r2rb1k1/pp1q1p1p/2n1p1p1/2bp4/5P2/PP1BPR1Q/1BPN2PP/R5K1 w - - bm Qxh7+; id \"WAC.014\";", "1R6/1brk2p1/4p2p/p1P1Pp2/P7/6P1/1P4P1/2R3K1 w - - bm Rxb7; id \"WAC.015\";", "r4rk1/ppp2ppp/2n5/2bqp3/8/P2PB3/1PP1NPPP/R2Q1RK1 w - - bm Nc3; id \"WAC.016\";", "1k5r/pppbn1pp/4q1r1/1P3p2/2NPp3/1QP5/P4PPP/R1B1R1K1 w - - bm Ne5; id \"WAC.017\";", "R7/P4k2/8/8/8/8/r7/6K1 w - - bm Rh8; id \"WAC.018\";", "r1b2rk1/ppbn1ppp/4p3/1QP4q/3P4/N4N2/5PPP/R1B2RK1 w - - bm c6; id \"WAC.019\";", "r2qkb1r/1ppb1ppp/p7/4p3/P1Q1P3/2P5/5PPP/R1B2KNR b kq - bm Bb5; id \"WAC.020\";", "5rk1/1b3p1p/pp3p2/3n1N2/1P6/P1qB1PP1/3Q3P/4R1K1 w - - bm Qh6; id \"WAC.021\";", "r1bqk2r/ppp1nppp/4p3/n5N1/2BPp3/P1P5/2P2PPP/R1BQK2R w KQkq - bm Ba2 Nxf7; id \"WAC.022\";", "r3nrk1/2p2p1p/p1p1b1p1/2NpPq2/3R4/P1N1Q3/1PP2PPP/4R1K1 w - - bm g4; id \"WAC.023\";", "6k1/1b1nqpbp/pp4p1/5P2/1PN5/4Q3/P5PP/1B2B1K1 b - - bm Bd4; id \"WAC.024\";", "3R1rk1/8/5Qpp/2p5/2P1p1q1/P3P3/1P2PK2/8 b - - bm Qh4+; id \"WAC.025\";", "3r2k1/1p1b1pp1/pq5p/8/3NR3/2PQ3P/PP3PP1/6K1 b - - bm Bf5; id \"WAC.026\";", "7k/pp4np/2p3p1/3pN1q1/3P4/Q7/1r3rPP/2R2RK1 w - - bm Qf8+; id \"WAC.027\";", "1r1r2k1/4pp1p/2p1b1p1/p3R3/RqBP4/4P3/1PQ2PPP/6K1 b - - bm Qe1+; id \"WAC.028\";", "r2q2k1/pp1rbppp/4pn2/2P5/1P3B2/6P1/P3QPBP/1R3RK1 w - - bm c6; id \"WAC.029\";", "1r3r2/4q1kp/b1pp2p1/5p2/pPn1N3/6P1/P3PPBP/2QRR1K1 w - - bm Nxd6; id \"WAC.030\";", "rb3qk1/pQ3ppp/4p3/3P4/8/1P3N2/1P3PPP/3R2K1 w - - bm Qxa8 d6 dxe6 g3; id \"WAC.031\";", "6k1/p4p1p/1p3np1/2q5/4p3/4P1N1/PP3PPP/3Q2K1 w - - bm Qd8+; id \"WAC.032\";", "8/p1q2pkp/2Pr2p1/8/P3Q3/6P1/5P1P/2R3K1 w - - bm Qe5+ Qf4; id \"WAC.033\";", "7k/1b1r2p1/p6p/1p2qN2/3bP3/3Q4/P5PP/1B1R3K b - - bm Bg1; id \"WAC.034\";", "r3r2k/2R3pp/pp1q1p2/8/3P3R/7P/PP3PP1/3Q2K1 w - - bm Rxh7+; id \"WAC.035\";", "3r4/2p1rk2/1pQq1pp1/7p/1P1P4/P4P2/6PP/R1R3K1 b - - bm Re1+; id \"WAC.036\";", "2r5/2rk2pp/1pn1pb2/pN1p4/P2P4/1N2B3/nPR1KPPP/3R4 b - - bm Nxd4+; id \"WAC.037\";", "4k3/p4prp/1p6/2b5/8/2Q3P1/P2R1PKP/4q3 w - - bm Qd3 Rd8+; id \"WAC.038\";", "r1br2k1/pp2bppp/2nppn2/8/2P1PB2/2N2P2/PqN1B1PP/R2Q1R1K w - - bm Na4; id \"WAC.039\";", "3r1r1k/1p4pp/p4p2/8/1PQR4/6Pq/P3PP2/2R3K1 b - - bm Rc8; id \"WAC.040\";", "1k6/5RP1/1P6/1K6/6r1/8/8/8 w - - bm Ka5 Kc5 b7; id \"WAC.041\";", "r1b1r1k1/pp1n1pbp/1qp3p1/3p4/1B1P4/Q3PN2/PP2BPPP/R4RK1 w - - bm Ba5; id \"WAC.042\";", "r2q3k/p2P3p/1p3p2/3QP1r1/8/B7/P5PP/2R3K1 w - - bm Be7 Qxa8; id \"WAC.043\";", "3rb1k1/pq3pbp/4n1p1/3p4/2N5/2P2QB1/PP3PPP/1B1R2K1 b - - bm dxc4; id \"WAC.044\";", "7k/2p1b1pp/8/1p2P3/1P3r2/2P3Q1/1P5P/R4qBK b - - bm Qxa1; id \"WAC.045\";", "r1bqr1k1/pp1nb1p1/4p2p/3p1p2/3P4/P1N1PNP1/1PQ2PP1/3RKB1R w K - bm Nb5; id \"WAC.046\";", "r1b2rk1/pp2bppp/2n1pn2/q5B1/2BP4/2N2N2/PP2QPPP/2R2RK1 b - - bm Nxd4; id \"WAC.047\";", "1rbq1rk1/p1p1bppp/2p2n2/8/Q1BP4/2N5/PP3PPP/R1B2RK1 b - - bm Rb4; id \"WAC.048\";", "2b3k1/4rrpp/p2p4/2pP2RQ/1pP1Pp1N/1P3P1P/1q6/6RK w - - bm Qxh7+; id \"WAC.049\";", "k4r2/1R4pb/1pQp1n1p/3P4/5p1P/3P2P1/r1q1R2K/8 w - - bm Rxb6+; id \"WAC.050\";", "r1bq1r2/pp4k1/4p2p/3pPp1Q/3N1R1P/2PB4/6P1/6K1 w - - bm Rg4+; id \"WAC.051\";", "r1k5/1p3q2/1Qpb4/3N1p2/5Pp1/3P2Pp/PPPK3P/4R3 w - - bm Re7 c4; id \"WAC.052\";", "6k1/6p1/p7/3Pn3/5p2/4rBqP/P4RP1/5QK1 b - - bm Re1; id \"WAC.053\";", "r3kr2/1pp4p/1p1p4/7q/4P1n1/2PP2Q1/PP4P1/R1BB2K1 b q - bm Qh1+; id \"WAC.054\";", "r3r1k1/pp1q1pp1/4b1p1/3p2B1/3Q1R2/8/PPP3PP/4R1K1 w - - bm Qxg7+; id \"WAC.055\";", "r1bqk2r/pppp1ppp/5n2/2b1n3/4P3/1BP3Q1/PP3PPP/RNB1K1NR b KQkq - bm Bxf2+; id \"WAC.056\";", "r3q1kr/ppp5/3p2pQ/8/3PP1b1/5R2/PPP3P1/5RK1 w - - bm Rf8+; id \"WAC.057\";", "8/8/2R5/1p2qp1k/1P2r3/2PQ2P1/5K2/8 w - - bm Qd1+; id \"WAC.058\";", "r1b2rk1/2p1qnbp/p1pp2p1/5p2/2PQP3/1PN2N1P/PB3PP1/3R1RK1 w - - bm Nd5; id \"WAC.059\";", "rn1qr1k1/1p2np2/2p3p1/8/1pPb4/7Q/PB1P1PP1/2KR1B1R w - - bm Qh8+; id \"WAC.060\";", "3qrbk1/ppp1r2n/3pP2p/3P4/2P4P/1P3Q2/PB6/R4R1K w - - bm Qf7+; id \"WAC.061\";", "6r1/3Pn1qk/p1p1P1rp/2Q2p2/2P5/1P4P1/P3R2P/5RK1 b - - bm Rxg3+; id \"WAC.062\";", "r1brnbk1/ppq2pp1/4p2p/4N3/3P4/P1PB1Q2/3B1PPP/R3R1K1 w - - bm Nxf7; id \"WAC.063\";", "8/6pp/3q1p2/3n1k2/1P6/3NQ2P/5PP1/6K1 w - - bm g4+; id \"WAC.064\";", "1r1r1qk1/p2n1p1p/bp1Pn1pQ/2pNp3/2P2P1N/1P5B/P6P/3R1RK1 w - - bm Ne7+; id \"WAC.065\";", "1k1r2r1/ppq5/1bp4p/3pQ3/8/2P2N2/PP4P1/R4R1K b - - bm Qxe5; id \"WAC.066\";", "3r2k1/p2q4/1p4p1/3rRp1p/5P1P/6PK/P3R3/3Q4 w - - bm Qb3 Rxd5; id \"WAC.067\";", "6k1/5ppp/1q6/2b5/8/2R1pPP1/1P2Q2P/7K w - - bm Qxe3; id \"WAC.068\";", "2k5/pppr4/4R3/4Q3/2pp2q1/8/PPP2PPP/6K1 w - - bm f3 h3; id \"WAC.069\";", "2kr3r/pppq1ppp/3p1n2/bQ2p3/1n1PP3/1PN1BN1P/1PP2PP1/2KR3R b - - bm Na2+; id \"WAC.070\";", "2kr3r/pp1q1ppp/5n2/1Nb5/2Pp1B2/7Q/P4PPP/1R3RK1 w - - bm Nxa7+; id \"WAC.071\";", "r3r1k1/pp1n1ppp/2p5/4Pb2/2B2P2/B1P5/P5PP/R2R2K1 w - - bm e6; id \"WAC.072\";", "r1q3rk/1ppbb1p1/4Np1p/p3pP2/P3P3/2N4R/1PP1Q1PP/3R2K1 w - - bm Qd2; id \"WAC.073\";", "5r1k/pp4pp/2p5/2b1P3/4Pq2/1PB1p3/P3Q1PP/3N2K1 b - - bm Rd8 Qf1+ Qxe4 a5 Bb6; id \"WAC.074; c0 \"Rd8 is probably best. Shredder says: 18/50 02:21 376.379.119 3.222.065 +10.49 Rf8d8 Kg1h1 Qf4xe4 Bc3a5 Rd8f8 h2h3 Qe4xe5 Ba5c3 Qe5f4 Nd1xe3 Bc5xe3 Qe2d1 Be3c5 Qd1e1\"\";", "r3r1k1/pppq1ppp/8/8/1Q4n1/7P/PPP2PP1/RNB1R1K1 b - - bm Qd6; id \"WAC.075\";", "r1b1qrk1/2p2ppp/pb1pnn2/1p2pNB1/3PP3/1BP5/PP2QPPP/RN1R2K1 w - - bm Bxf6; id \"WAC.076\";", "3r2k1/ppp2ppp/6q1/b4n2/3nQB2/2p5/P4PPP/RN3RK1 b - - bm Ng3; id \"WAC.077\";", "r2q3r/ppp2k2/4nbp1/5Q1p/2P1NB2/8/PP3P1P/3RR1K1 w - - bm Ng5+; id \"WAC.078\";", "r3k2r/pbp2pp1/3b1n2/1p6/3P3p/1B2N1Pq/PP1PQP1P/R1B2RK1 b kq - bm Qxh2+; id \"WAC.079\";", "r4rk1/p1B1bpp1/1p2pn1p/8/2PP4/3B1P2/qP2QP1P/3R1RK1 w - - bm Ra1; id \"WAC.080\";", "r4rk1/1bR1bppp/4pn2/1p2N3/1P6/P3P3/4BPPP/3R2K1 b - - bm Bd6; id \"WAC.081\";", "3rr1k1/pp3pp1/4b3/8/2P1B2R/6QP/P3q1P1/5R1K w - - bm Bh7+; id \"WAC.082\";", "3rr1k1/ppqbRppp/2p5/8/3Q1n2/2P3N1/PPB2PPP/3R2K1 w - - bm Qxd7; id \"WAC.083\";", "r2q1r1k/2p1b1pp/p1n5/1p1Q1bN1/4n3/1BP1B3/PP3PPP/R4RK1 w - - bm Qg8+; id \"WAC.084\";", "kr2R3/p4r2/2pq4/2N2p1p/3P2p1/Q5P1/5P1P/5BK1 w - - bm Na6; id \"WAC.085\";", "8/p7/1ppk1n2/5ppp/P1PP4/2P1K1P1/5N1P/8 b - - bm Ng4+; id \"WAC.086\";", "8/p3k1p1/4r3/2ppNpp1/PP1P4/2P3KP/5P2/8 b - - bm Rxe5; id \"WAC.087\";", "r6k/p1Q4p/2p1b1rq/4p3/B3P3/4P3/PPP3P1/4RRK1 b - - bm Rxg2+; id \"WAC.088\";", "1r3b1k/p4rpp/4pp2/3q4/2ppbPPQ/6RK/PP5P/2B1NR2 b - - bm g5; id \"WAC.089\";", "3qrrk1/1pp2pp1/1p2bn1p/5N2/2P5/P1P3B1/1P4PP/2Q1RRK1 w - - bm Nxg7; id \"WAC.090\";", "2qr2k1/4b1p1/2p2p1p/1pP1p3/p2nP3/PbQNB1PP/1P3PK1/4RB2 b - - bm Be6; id \"WAC.091\";", "r4rk1/1p2ppbp/p2pbnp1/q7/3BPPP1/2N2B2/PPP4P/R2Q1RK1 b - - bm Bxg4; id \"WAC.092\";", "r1b1k1nr/pp3pQp/4pq2/3pn3/8/P1P5/2P2PPP/R1B1KBNR w KQkq - bm Bh6; id \"WAC.093\";", "8/k7/p7/3Qp2P/n1P5/3KP3/1q6/8 b - - bm e4+; id \"WAC.094\";", "2r5/1r6/4pNpk/3pP1qp/8/2P1QP2/5PK1/R7 w - - bm Ng4+; id \"WAC.095\";", "r1b4k/ppp2Bb1/6Pp/3pP3/1qnP1p1Q/8/PPP3P1/1K1R3R w - - bm Qd8+ b3; id \"WAC.096\";", "6k1/5p2/p5np/4B3/3P4/1PP1q3/P3r1QP/6RK w - - bm Qa8+; id \"WAC.097\";", "1r3rk1/5pb1/p2p2p1/Q1n1q2p/1NP1P3/3p1P1B/PP1R3P/1K2R3 b - - bm Nxe4; id \"WAC.098\";", "r1bq1r1k/1pp1Np1p/p2p2pQ/4R3/n7/8/PPPP1PPP/R1B3K1 w - - bm Rh5; id \"WAC.099\";", "8/k1b5/P4p2/1Pp2p1p/K1P2P1P/8/3B4/8 w - - bm Be3 b6+; c0 \"b6+ is probably better.\"; id \"WAC.100\";", "5rk1/p5pp/8/8/2Pbp3/1P4P1/7P/4RN1K b - - bm Bc3; id \"WAC.101\";", "2Q2n2/2R4p/1p1qpp1k/8/3P3P/3B2P1/5PK1/r7 w - - bm Qxf8+; id \"WAC.102\";", "6k1/2pb1r1p/3p1PpQ/p1nPp3/1q2P3/2N2P2/PrB5/2K3RR w - - bm Qxg6+; id \"WAC.103\";", "b4r1k/pq2rp2/1p1bpn1p/3PN2n/2P2P2/P2B3K/1B2Q2N/3R2R1 w - - bm Qxh5; id \"WAC.104\";", "r2r2k1/pb3ppp/1p1bp3/7q/3n2nP/PP1B2P1/1B1N1P2/RQ2NRK1 b - - bm Bxg3 Qxh4; id \"WAC.105\";", "4rrk1/pppb4/7p/3P2pq/3Qn3/P5P1/1PP4P/R3RNNK b - - bm Nf2+; id \"WAC.106\";", "5n2/pRrk2p1/P4p1p/4p3/3N4/5P2/6PP/6K1 w - - bm Nb5; id \"WAC.107\";", "r5k1/1q4pp/2p5/p1Q5/2P5/5R2/4RKPP/r7 w - - bm Qe5; id \"WAC.108\";", "rn2k1nr/pbp2ppp/3q4/1p2N3/2p5/QP6/PB1PPPPP/R3KB1R b KQkq - bm c3; id \"WAC.109\";", "2kr4/bp3p2/p2p2b1/P7/2q5/1N4B1/1PPQ2P1/2KR4 b - - bm Be3; id \"WAC.110\";", "6k1/p5p1/5p2/2P2Q2/3pN2p/3PbK1P/7P/6q1 b - - bm Qd1+ Qf1+; c0 \"Qd1+ also wins, but Qf1 is faster and better.\"; id \"WAC.111\";", "r4kr1/ppp5/4bq1b/7B/2PR1Q1p/2N3P1/PP3P1P/2K1R3 w - - bm Rxe6; id \"WAC.112\";", "rnbqkb1r/1p3ppp/5N2/1p2p1B1/2P5/8/PP2PPPP/R2QKB1R b KQkq - bm Qxf6; id \"WAC.113\";", "r1b1rnk1/1p4pp/p1p2p2/3pN2n/3P1PPq/2NBPR1P/PPQ5/2R3K1 w - - bm Bxh7+; id \"WAC.114\";", "4N2k/5rpp/1Q6/p3q3/8/P5P1/1P3P1P/5K2 w - - bm Nd6; id \"WAC.115\";", "r2r2k1/2p2ppp/p7/1p2P1n1/P6q/5P2/1PB1QP1P/R5RK b - - bm Rd2; id \"WAC.116\";", "3r1rk1/q4ppp/p1Rnp3/8/1p6/1N3P2/PP3QPP/3R2K1 b - - bm Ne4; id \"WAC.117\";", "r5k1/pb2rpp1/1p6/2p4q/5R2/2PB2Q1/P1P3PP/5R1K w - - bm Rh4; id \"WAC.118\";", "r2qr1k1/p1p2ppp/2p5/2b5/4nPQ1/3B4/PPP3PP/R1B2R1K b - - bm Qxd3; id \"WAC.119\";", "r4rk1/1bn2qnp/3p1B1Q/p2P1pP1/1pp5/5N1P/PPB2P2/2KR3R w - - bm Rhg1 g6; id \"WAC.120\";", "6k1/5p1p/2bP2pb/4p3/2P5/1p1pNPPP/1P1Q1BK1/1q6 b - - bm Bxf3+; id \"WAC.121\";", "1k6/ppp4p/1n2pq2/1N2Rb2/2P2Q2/8/P4KPP/3r1B2 b - - bm Rxf1+; id \"WAC.122\";", "6k1/1b2rp2/1p4p1/3P4/PQ4P1/2N2q2/5P2/3R2K1 b - - bm Bxd5 Rc7 Re6; id \"WAC.123\";", "6k1/3r4/2R5/P5P1/1P4p1/8/4rB2/6K1 b - - bm g3; id \"WAC.124\";", "r1bqr1k1/pp3ppp/1bp5/3n4/3B4/2N2P1P/PPP1B1P1/R2Q1RK1 b - - bm Bxd4+; id \"WAC.125\";", "r5r1/pQ5p/1qp2R2/2k1p3/4P3/2PP4/P1P3PP/6K1 w - - bm Rxc6+; id \"WAC.126\";", "2k4r/1pr1n3/p1p1q2p/5pp1/3P1P2/P1P1P3/1R2Q1PP/1RB3K1 w - - bm Rxb7; id \"WAC.127\";", "6rk/1pp2Qrp/3p1B2/1pb1p2R/3n1q2/3P4/PPP3PP/R6K w - - bm Qg6; id \"WAC.128\";", "3r1r1k/1b2b1p1/1p5p/2p1Pp2/q1B2P2/4P2P/1BR1Q2K/6R1 b - - bm Bf3; id \"WAC.129\";", "6k1/1pp3q1/5r2/1PPp4/3P1pP1/3Qn2P/3B4/4R1K1 b - - bm Qh6 Qh8; id \"WAC.130\";", "2rq1bk1/p4p1p/1p4p1/3b4/3B1Q2/8/P4PpP/3RR1K1 w - - bm Re8; id \"WAC.131\";", "4r1k1/5bpp/2p5/3pr3/8/1B3pPq/PPR2P2/2R2QK1 b - - bm Qxf1+ Re1; id \"WAC.132\";", "r1b1k2r/1pp1q2p/p1n3p1/3QPp2/8/1BP3B1/P5PP/3R1RK1 w kq - bm Bh4; id \"WAC.133\";", "3r2k1/p6p/2Q3p1/4q3/2P1p3/P3Pb2/1P3P1P/2K2BR1 b - - bm Rd1+; id \"WAC.134\";", "3r1r1k/N2qn1pp/1p2np2/2p5/2Q1P2N/3P4/PP4PP/3R1RK1 b - - bm Nd4; id \"WAC.135\";", "6kr/1q2r1p1/1p2N1Q1/5p2/1P1p4/6R1/7P/2R3K1 w - - bm Rc8+; id \"WAC.136\";", "3b1rk1/1bq3pp/5pn1/1p2rN2/2p1p3/2P1B2Q/1PB2PPP/R2R2K1 w - - bm Rd7; id \"WAC.137\";", "r1bq3r/ppppR1p1/5n1k/3P4/6pP/3Q4/PP1N1PP1/5K1R w - - bm Qe3+ h5; id \"WAC.138\";", "rnb3kr/ppp2ppp/1b6/3q4/3pN3/Q4N2/PPP2KPP/R1B1R3 w - - bm Nf6+; id \"WAC.139\";", "r2b1rk1/pq4p1/4ppQP/3pB1p1/3P4/2R5/PP3PP1/5RK1 w - - bm Bc7 Rc7; id \"WAC.140\";", "4r1k1/p1qr1p2/2pb1Bp1/1p5p/3P1n1R/1B3P2/PP3PK1/2Q4R w - - bm Qxf4; id \"WAC.141\";", "r2q3n/ppp2pk1/3p4/5Pr1/2NP1Qp1/2P2pP1/PP3K2/4R2R w - - bm Re8 f6+; id \"WAC.142\";", "5b2/pp2r1pk/2pp1pRp/4rP1N/2P1P3/1P4QP/P3q1P1/5R1K w - - bm Rxh6+; id \"WAC.143\";", "r2q1rk1/pp3ppp/2p2b2/8/B2pPPb1/7P/PPP1N1P1/R2Q1RK1 b - - bm d3; id \"WAC.144\";", "r1bq4/1p4kp/3p1n2/p4pB1/2pQ4/8/1P4PP/4RRK1 w - - bm Re8; id \"WAC.145\";", "8/8/2Kp4/3P1B2/2P2k2/5p2/8/8 w - - bm Bc8 Bd3 Bh3; id \"WAC.146\";", "r2r2k1/ppqbppbp/2n2np1/2pp4/6P1/1P1PPNNP/PBP2PB1/R2QK2R b KQ - bm Nxg4; id \"WAC.147\";", "2r1k3/6pr/p1nBP3/1p3p1p/2q5/2P5/P1R4P/K2Q2R1 w - - bm Rxg7; id \"WAC.148\";", "6k1/6p1/2p4p/4Pp2/4b1qP/2Br4/1P2RQPK/8 b - - bm Bxg2; id \"WAC.149\";", "r3r1k1/5p2/pQ1b2pB/1p6/4p3/6P1/Pq2BP1P/2R3K1 b - - bm Ba3 Be5 Bf8 e3; c0 \"All win but e3 is best.\"; id \"WAC.150\";", "8/3b2kp/4p1p1/pr1n4/N1N4P/1P4P1/1K3P2/3R4 w - - bm Nc3; id \"WAC.151\";", "1br2rk1/1pqb1ppp/p3pn2/8/1P6/P1N1PN1P/1B3PP1/1QRR2K1 w - - bm Ne4; id \"WAC.152\";", "2r3k1/q4ppp/p3p3/pnNp4/2rP4/2P2P2/4R1PP/2R1Q1K1 b - - bm Nxd4; id \"WAC.153\";", "r1b2rk1/2p2ppp/p7/1p6/3P3q/1BP3bP/PP3QP1/RNB1R1K1 w - - bm Qxf7+; id \"WAC.154\";", "5bk1/1rQ4p/5pp1/2pP4/3n1PP1/7P/1q3BB1/4R1K1 w - - bm d6; id \"WAC.155\";", "r1b1qN1k/1pp3p1/p2p3n/4p1B1/8/1BP4Q/PP3KPP/8 w - - bm Qxh6+; id \"WAC.156\";", "5rk1/p4ppp/2p1b3/3Nq3/4P1n1/1p1B2QP/1PPr2P1/1K2R2R w - - bm Ne7+; id \"WAC.157\";", "5rk1/n1p1R1bp/p2p4/1qpP1QB1/7P/2P3P1/PP3P2/6K1 w - - bm Rxg7+; id \"WAC.158\";", "r1b2r2/5P1p/ppn3pk/2p1p1Nq/1bP1PQ2/3P4/PB4BP/1R3RK1 w - - bm Ne6+; id \"WAC.159\";", "qn1kr2r/1pRbb3/pP5p/P2pP1pP/3N1pQ1/3B4/3B1PP1/R5K1 w - - bm Qxd7+; id \"WAC.160\";", "3r3k/3r1P1p/pp1Nn3/2pp4/7Q/6R1/Pq4PP/5RK1 w - - bm Qxd8+; id \"WAC.161\";", "r3kbnr/p4ppp/2p1p3/8/Q1B3b1/2N1B3/PP3PqP/R3K2R w KQkq - bm Bd5; id \"WAC.162\";", "5rk1/2p4p/2p4r/3P4/4p1b1/1Q2NqPp/PP3P1K/R4R2 b - - bm Qg2+; id \"WAC.163\";", "8/6pp/4p3/1p1n4/1NbkN1P1/P4P1P/1PR3K1/r7 w - - bm Rxc4+; id \"WAC.164\";", "1r5k/p1p3pp/8/8/4p3/P1P1R3/1P1Q1qr1/2KR4 w - - bm Qd8+ Re2; id \"WAC.165\";", "r3r1k1/5pp1/p1p4p/2Pp4/8/q1NQP1BP/5PP1/4K2R b K - bm d4; id \"WAC.166\";", "7Q/ppp2q2/3p2k1/P2Ppr1N/1PP5/7R/5rP1/6K1 b - - bm Rxg2+; id \"WAC.167\";", "r3k2r/pb1q1p2/8/2p1pP2/4p1p1/B1P1Q1P1/P1P3K1/R4R2 b kq - bm Qd2+; id \"WAC.168\";", "5rk1/1pp3bp/3p2p1/2PPp3/1P2P3/2Q1B3/4q1PP/R5K1 b - - bm Bh6; id \"WAC.169\";", "5r1k/6Rp/1p2p3/p2pBp2/1qnP4/4P3/Q4PPP/6K1 w - - bm Qxc4; id \"WAC.170\";", "2rq4/1b2b1kp/p3p1p1/1p1nNp2/7P/1B2B1Q1/PP3PP1/3R2K1 w - - bm Bh6+; id \"WAC.171\";", "5r1k/p5pp/8/1P1pq3/P1p2nR1/Q7/5BPP/6K1 b - - bm Qe1+; id \"WAC.172\";", "2r1b3/1pp1qrk1/p1n1P1p1/7R/2B1p3/4Q1P1/PP3PP1/3R2K1 w - - bm Qh6+; id \"WAC.173\";", "2r2rk1/6p1/p3pq1p/1p1b1p2/3P1n2/PP3N2/3N1PPP/1Q2RR1K b - - bm Nxg2; id \"WAC.174\";", "r5k1/pppb3p/2np1n2/8/3PqNpP/3Q2P1/PPP5/R4RK1 w - - bm Nh5; id \"WAC.175\";", "r1bq3r/ppp2pk1/3p1pp1/8/2BbPQ2/2NP2P1/PPP4P/R4R1K b - - bm Rxh2+; id \"WAC.176\";", "r1b3r1/4qk2/1nn1p1p1/3pPp1P/p4P2/1p3BQN/PKPBN3/3R3R b - - bm Qa3+; id \"WAC.177\";", "3r2k1/p1rn1p1p/1p2pp2/6q1/3PQNP1/5P2/P1P4R/R5K1 w - - bm Nxe6; id \"WAC.178\";", "r1b2r1k/pp4pp/3p4/3B4/8/1QN3Pn/PP3q1P/R3R2K b - - bm Qg1+; id \"WAC.179\";", "r1q2rk1/p3bppb/3p1n1p/2nPp3/1p2P1P1/6NP/PP2QPB1/R1BNK2R b KQ - bm Nxd5; id \"WAC.180\";", "r3k2r/2p2p2/p2p1n2/1p2p3/4P2p/1PPPPp1q/1P5P/R1N2QRK b kq - bm Ng4; id \"WAC.181\";", "r1b2rk1/ppqn1p1p/2n1p1p1/2b3N1/2N5/PP1BP3/1B3PPP/R2QK2R w KQ - bm Qh5; id \"WAC.182\";", "1r2k1r1/5p2/b3p3/1p2b1B1/3p3P/3B4/PP2KP2/2R3R1 w - - bm Bf6; id \"WAC.183\";", "4kn2/r4p1r/p3bQ2/q1nNP1Np/1p5P/8/PPP3P1/2KR3R w - - bm Qe7+; id \"WAC.184\";", "1r1rb1k1/2p3pp/p2q1p2/3PpP1Q/Pp1bP2N/1B5R/1P4PP/2B4K w - - bm Ng6 Qxh7+; c0 \"Ng6 is probably slightly better than Qxh7+\"; id \"WAC.185\";", "r5r1/p1q2p1k/1p1R2pB/3pP3/6bQ/2p5/P1P1NPPP/6K1 w - - bm Bf8+; id \"WAC.186\";", "6k1/5p2/p3p3/1p3qp1/2p1Qn2/2P1R3/PP1r1PPP/4R1K1 b - - bm Nh3+; id \"WAC.187\";", "3RNbk1/pp3p2/4rQpp/8/1qr5/7P/P4P2/3R2K1 w - - bm Qg7+; id \"WAC.188\";", "3r1k2/1ppPR1n1/p2p1rP1/3P3p/4Rp1N/5K2/P1P2P2/8 w - - bm Re8+; id \"WAC.189\";", "8/p2b2kp/1q1p2p1/1P1Pp3/4P3/3B2P1/P2Q3P/2Nn3K b - - bm Bh3; id \"WAC.190\";", "2r1Rn1k/1p1q2pp/p7/5p2/3P4/1B4P1/P1P1QP1P/6K1 w - - bm Qc4; id \"WAC.191\";", "r3k3/ppp2Npp/4Bn2/2b5/1n1pp3/N4P2/PPP3qP/R2QKR2 b Qq - bm Nd3+; id \"WAC.192\";", "5bk1/p4ppp/Qp6/4B3/1P6/Pq2P1P1/2rr1P1P/R4RK1 b - - bm Qxe3; id \"WAC.193\";", "5rk1/ppq2ppp/2p5/4bN2/4P3/6Q1/PPP2PPP/3R2K1 w - - bm Nh6+; id \"WAC.194\";", "3r1rk1/1p3p2/p3pnnp/2p3p1/2P2q2/1P5P/PB2QPPN/3RR1K1 w - - bm g3; id \"WAC.195\";", "rr4k1/p1pq2pp/Q1n1pn2/2bpp3/4P3/2PP1NN1/PP3PPP/R1B1K2R b KQ - bm Nb4; id \"WAC.196\";", "7k/1p4p1/7p/3P1n2/4Q3/2P2P2/PP3qRP/7K b - - bm Qf1+; id \"WAC.197\";", "2br2k1/ppp2p1p/4p1p1/4P2q/2P1Bn2/2Q5/PP3P1P/4R1RK b - - bm Rd3; id \"WAC.198\";", "r1br2k1/pp2nppp/2n5/1B1q4/Q7/4BN2/PP3PPP/2R2RK1 w - - bm Bxc6 Rcd1 Rfd1; id \"WAC.199\";", "2rqrn1k/pb4pp/1p2pp2/n2P4/2P3N1/P2B2Q1/1B3PPP/2R1R1K1 w - - bm Bxf6; id \"WAC.200\";", "2b2r1k/4q2p/3p2pQ/2pBp3/8/6P1/1PP2P1P/R5K1 w - - bm Ra7; id \"WAC.201\";", "QR2rq1k/2p3p1/3p1pPp/8/4P3/8/P1r3PP/1R4K1 b - - bm Rxa2; id \"WAC.202\";", "r4rk1/5ppp/p3q1n1/2p2NQ1/4n3/P3P3/1B3PPP/1R3RK1 w - - bm Qh6; id \"WAC.203\";", "r1b1qrk1/1p3ppp/p1p5/3Nb3/5N2/P7/1P4PQ/K1R1R3 w - - bm Rxe5; id \"WAC.204\";", "r3rnk1/1pq2bb1/p4p2/3p1Pp1/3B2P1/1NP4R/P1PQB3/2K4R w - - bm Qxg5; id \"WAC.205\";", "1Qq5/2P1p1kp/3r1pp1/8/8/7P/p4PP1/2R3K1 b - - bm Rc6; id \"WAC.206\";", "r1bq2kr/p1pp1ppp/1pn1p3/4P3/2Pb2Q1/BR6/P4PPP/3K1BNR w - - bm Qxg7+; id \"WAC.207\";", "3r1bk1/ppq3pp/2p5/2P2Q1B/8/1P4P1/P6P/5RK1 w - - bm Bf7+; id \"WAC.208\";", "4kb1r/2q2p2/r2p4/pppBn1B1/P6P/6Q1/1PP5/2KRR3 w k - bm Rxe5+; id \"WAC.209\";", "3r1rk1/pp1q1ppp/3pn3/2pN4/5PP1/P5PQ/1PP1B3/1K1R4 w - - bm Rh1; id \"WAC.210\";", "r1bqrk2/pp1n1n1p/3p1p2/P1pP1P1Q/2PpP1NP/6R1/2PB4/4RBK1 w - - bm Qxf7+; id \"WAC.211\";", "rn1qr2Q/pbppk1p1/1p2pb2/4N3/3P4/2N5/PPP3PP/R4RK1 w - - bm Qxg7+; id \"WAC.212\";", "3r1r1k/1b4pp/ppn1p3/4Pp1R/Pn5P/3P4/4QP2/1qB1NKR1 w - - bm Rxh7+; id \"WAC.213\";", "r2r2k1/1p2qpp1/1np1p1p1/p3N3/2PPN3/bP5R/4QPPP/4R1K1 w - - bm Ng5; id \"WAC.214\";", "3r2k1/pb1q1pp1/1p2pb1p/8/3N4/P2QB3/1P3PPP/1Br1R1K1 w - - bm Qh7+; id \"WAC.215\";", "r2qr1k1/1b1nbppp/p3pn2/1p1pN3/3P1B2/2PB1N2/PP2QPPP/R4RK1 w - - bm Nxf7 a4; id \"WAC.216\";", "r3kb1r/1pp3p1/p3bp1p/5q2/3QN3/1P6/PBP3P1/3RR1K1 w kq - bm Qd7+; id \"WAC.217\";", "6k1/pp5p/2p3q1/6BP/2nPr1Q1/8/PP3R1K/8 w - - bm Bh6; id \"WAC.218\";", "7k/p4q1p/1pb5/2p5/4B2Q/2P1B3/P6P/7K b - - bm Qf1+; id \"WAC.219\";", "3rr1k1/ppp2ppp/8/5Q2/4n3/1B5R/PPP1qPP1/5RK1 b - - bm Qxf1+; id \"WAC.220\";", "r3k3/P5bp/2N1bp2/4p3/2p5/6NP/1PP2PP1/3R2K1 w q - bm Rd8+; id \"WAC.221\";", "2r1r2k/1q3ppp/p2Rp3/2p1P3/6QB/p3P3/bP3PPP/3R2K1 w - - bm Bf6; id \"WAC.222\";", "r1bqk2r/pp3ppp/5n2/8/1b1npB2/2N5/PP1Q2PP/1K2RBNR w kq - bm Nxe4; id \"WAC.223\";", "5rk1/p1q3pp/1p1r4/2p1pp1Q/1PPn1P2/3B3P/P2R2P1/3R2K1 b - - bm Rh6 e4; id \"WAC.224\";", "4R3/4q1kp/6p1/1Q3b2/1P1b1P2/6KP/8/8 b - - bm Qh4+; id \"WAC.225\";", "2b2rk1/p1p4p/2p1p1p1/br2N1Q1/1p2q3/8/PB3PPP/3R1RK1 w - - bm Nf7; id \"WAC.226\";", "2k1rb1r/ppp3pp/2np1q2/5b2/2B2P2/2P1BQ2/PP1N1P1P/2KR3R b - - bm d5; id \"WAC.227\";", "r4rk1/1bq1bp1p/4p1p1/p2p4/3BnP2/1N1B3R/PPP3PP/R2Q2K1 w - - bm Bxe4; id \"WAC.228\";", "8/8/8/1p5r/p1p1k1pN/P2pBpP1/1P1K1P2/8 b - - bm Rxh4 b4; id \"WAC.229\";", "2b5/1r6/2kBp1p1/p2pP1P1/2pP4/1pP3K1/1R3P2/8 b - - bm Rb4; id \"WAC.230\";", "r4rk1/1b1nqp1p/p5p1/1p2PQ2/2p5/5N2/PP3PPP/R1BR2K1 w - - bm Bg5; id \"WAC.231\";", "1R2rq1k/2p3p1/Q2p1pPp/8/4P3/8/P1r3PP/1R4K1 w - - bm Qb5 Rxe8; id \"WAC.232\";", "5rk1/p1p2r1p/2pp2p1/4p3/PPPnP3/3Pq1P1/1Q1R1R1P/4NK2 b - - bm Nb3; id \"WAC.233\";", "2kr1r2/p6p/5Pp1/2p5/1qp2Q1P/7R/PP6/1KR5 w - - bm Rb3; id \"WAC.234\";", "5r2/1p1RRrk1/4Qq1p/1PP3p1/8/4B3/1b3P1P/6K1 w - - bm Qe4 Qxf7+ Rxf7+; id \"WAC.235\";", "1R6/p5pk/4p2p/4P3/8/2r3qP/P3R1b1/4Q1K1 b - - bm Rc1; id \"WAC.236\";", "r5k1/pQp2qpp/8/4pbN1/3P4/6P1/PPr4P/1K1R3R b - - bm Rc1+; id \"WAC.237\";", "1k1r4/pp1r1pp1/4n1p1/2R5/2Pp1qP1/3P2QP/P4PB1/1R4K1 w - - bm Bxb7; id \"WAC.238\";", "8/6k1/5pp1/Q6p/5P2/6PK/P4q1P/8 b - - bm Qf1+; id \"WAC.239\";", "2b4k/p1b2p2/2p2q2/3p1PNp/3P2R1/3B4/P1Q2PKP/4r3 w - - bm Qxc6; id \"WAC.240\";", "2rq1rk1/pp3ppp/2n2b2/4NR2/3P4/PB5Q/1P4PP/3R2K1 w - - bm Qxh7+; id \"WAC.241\";", "r1b1r1k1/pp1nqp2/2p1p1pp/8/4N3/P1Q1P3/1P3PPP/1BRR2K1 w - - bm Rxd7; id \"WAC.242\";", "1r3r1k/3p4/1p1Nn1R1/4Pp1q/pP3P1p/P7/5Q1P/6RK w - - bm Qe2; id \"WAC.243\";", "r6r/pp3ppp/3k1b2/2pb4/B4Pq1/2P1Q3/P5PP/1RBR2K1 w - - bm Qxc5+; id \"WAC.244\";", "4rrn1/ppq3bk/3pPnpp/2p5/2PB4/2NQ1RPB/PP5P/5R1K w - - bm Qxg6+; id \"WAC.245\";", "6R1/4qp1p/ppr1n1pk/8/1P2P1QP/6N1/P4PP1/6K1 w - - bm Qh5+; id \"WAC.246\";", "2k1r3/1p2Bq2/p2Qp3/Pb1p1p1P/2pP1P2/2P5/2P2KP1/1R6 w - - bm Rxb5; id \"WAC.247\";", "5r1k/1p4pp/3q4/3Pp1R1/8/8/PP4PP/4Q1K1 b - - bm Qc5+; id \"WAC.248\";", "r4rk1/pbq2pp1/1ppbpn1p/8/2PP4/1P1Q1N2/PBB2PPP/R3R1K1 w - - bm c5 d5; id \"WAC.249\";", "1b5k/7P/p1p2np1/2P2p2/PP3P2/4RQ1R/q2r3P/6K1 w - - bm Qxc6 Re8+; id \"WAC.250\";", "k7/p4p2/P1q1b1p1/3p3p/3Q4/7P/5PP1/1R4K1 w - - bm Qe5 Qf4; id \"WAC.251\";", "1rb1r1k1/p1p2ppp/5n2/2pP4/5P2/2QB4/qNP3PP/2KRB2R b - - bm Bg4 Re2; c0 \"Bg4 wins, but Re2 is far better.\"; id \"WAC.252\";", "k5r1/p4b2/2P5/5p2/3P1P2/4QBrq/P5P1/4R1K1 w - - bm Qe8+; id \"WAC.253\";", "r6k/pp3p1p/2p1bp1q/b3p3/4Pnr1/2PP2NP/PP1Q1PPN/R2B2RK b - - bm Nxh3; id \"WAC.254\";", "3r3r/p4pk1/5Rp1/3q4/1p1P2RQ/5N2/P1P4P/2b4K w - - bm Rfxg6+; id \"WAC.255\";", "3r1rk1/1pb1qp1p/2p3p1/p7/P2Np2R/1P5P/1BP2PP1/3Q1BK1 w - - bm Nf5; id \"WAC.256\";", "4r1k1/pq3p1p/2p1r1p1/2Q1p3/3nN1P1/1P6/P1P2P1P/3RR1K1 w - - bm Rxd4; id \"WAC.257\";", "r3brkn/1p5p/2p2Ppq/2Pp3B/3Pp2Q/4P1R1/6PP/5R1K w - - bm Bxg6; id \"WAC.258\";", "r1bq1rk1/ppp2ppp/2np4/2bN1PN1/2B1P3/3p4/PPP2nPP/R1BQ1K1R w - - bm Qh5; id \"WAC.259\";", "2r2b1r/p1Nk2pp/3p1p2/N2Qn3/4P3/q6P/P4PP1/1R3K1R w - - bm Qe6+; id \"WAC.260\";", "r5k1/1bp3pp/p2p4/1p6/5p2/1PBP1nqP/1PP3Q1/R4R1K b - - bm Nd4; id \"WAC.261\";", "6k1/p1B1b2p/2b3r1/2p5/4p3/1PP1N1Pq/P2R1P2/3Q2K1 b - - bm Rh6; id \"WAC.262\";", "rnbqr2k/pppp1Qpp/8/b2NN3/2B1n3/8/PPPP1PPP/R1B1K2R w KQ - bm Qg8+; id \"WAC.263\";", "r2r2k1/1R2qp2/p5pp/2P5/b1PN1b2/P7/1Q3PPP/1B1R2K1 b - - bm Qe5 Rab8; id \"WAC.264\";", "2r1k2r/2pn1pp1/1p3n1p/p3PP2/4q2B/P1P5/2Q1N1PP/R4RK1 w k - bm exf6; id \"WAC.265\";", "r3q2r/2p1k1p1/p5p1/1p2Nb2/1P2nB2/P7/2PNQbPP/R2R3K b - - bm Rxh2+; id \"WAC.266\";", "2r1kb1r/pp3ppp/2n1b3/1q1N2B1/1P2Q3/8/P4PPP/3RK1NR w Kk - bm Nc7+; id \"WAC.267\";", "2r3kr/ppp2n1p/7B/5q1N/1bp5/2Pp4/PP2RPPP/R2Q2K1 w - - bm Re8+; id \"WAC.268\";", "2kr2nr/pp1n1ppp/2p1p3/q7/1b1P1B2/P1N2Q1P/1PP1BPP1/R3K2R w KQ - bm axb4; id \"WAC.269\";", "2r1r1k1/pp1q1ppp/3p1b2/3P4/3Q4/5N2/PP2RPPP/4R1K1 w - - bm Qg4; id \"WAC.270\";", "2kr4/ppp3Pp/4RP1B/2r5/5P2/1P6/P2p4/3K4 w - - bm Rd6; id \"WAC.271\";", "nrq4r/2k1p3/1p1pPnp1/pRpP1p2/P1P2P2/2P1BB2/1R2Q1P1/6K1 w - - bm Bxc5; id \"WAC.272\";", "2k4B/bpp1qp2/p1b5/7p/1PN1n1p1/2Pr4/P5PP/R3QR1K b - - bm Ng3+ g3; id \"WAC.273\";", "8/1p6/p5R1/k7/Prpp4/K7/1NP5/8 w - - am Rd6; bm Rb6 Rg5+; id \"WAC.274\";", "r1b2rk1/1p1n1ppp/p1p2q2/4p3/P1B1Pn2/1QN2N2/1P3PPP/3R1RK1 b - - bm Nc5 Nxg2 b5; id \"WAC.275\";", "r5k1/pp1RR1pp/1b6/6r1/2p5/B6P/P4qPK/3Q4 w - - bm Qd5+; id \"WAC.276\";", "1r4r1/p2kb2p/bq2p3/3p1p2/5P2/2BB3Q/PP4PP/3RKR2 b - - bm Rg3 Rxg2; c0 \"This one is questionable.\"; c1 \"Rybka 1.2 says: 20 09:39 45.122.112 79.881 +0.55 Rg8g3 Qh3xg3 Be7h4 Bd3xa6 Bh4xg3+ h2xg3 Qb6xa6 Rf1h1 Kd7c6 Rh1xh7 Qa6xa2 Rd1c1 Kc6b5 Bc3e5\"; id \"WAC.277\";", "r2qkb1r/pppb2pp/2np1n2/5pN1/2BQP3/2N5/PPP2PPP/R1B1K2R w KQkq - bm Bf7+; id \"WAC.278\";", "r7/4b3/2p1r1k1/1p1pPp1q/1P1P1P1p/PR2NRpP/2Q3K1/8 w - - bm Nxf5 Rc3; id \"WAC.279\";", "r1r2bk1/5p1p/pn4p1/N2b4/3Pp3/B3P3/2q1BPPP/RQ3RK1 b - - bm Bxa3; id \"WAC.280\";", "2R5/2R4p/5p1k/6n1/8/1P2QPPq/r7/6K1 w - - bm Rxh7+; id \"WAC.281\";", "6k1/2p3p1/1p1p1nN1/1B1P4/4PK2/8/2r3b1/7R w - - bm Rh8+; id \"WAC.282\";", "3q1rk1/4bp1p/1n2P2Q/3p1p2/6r1/Pp2R2N/1B4PP/7K w - - bm Ng5; id \"WAC.283\";", "3r3k/pp4pp/8/1P6/3N4/Pn2P1qb/1B1Q2B1/2R3K1 w - - bm Nf5; id \"WAC.284\";", "2rr3k/1b2bppP/p2p1n2/R7/3P4/1qB2P2/1P4Q1/1K5R w - - bm Qxg7+; id \"WAC.285\";", "3r1k2/1p6/p4P2/2pP2Qb/8/1P1KB3/P6r/8 b - - bm Rxd5+; id \"WAC.286\";", "rn3k1r/pp2bBpp/2p2n2/q5N1/3P4/1P6/P1P3PP/R1BQ1RK1 w - - bm Bc4 Bd2 Qe2 Qg4 Qh5; c0 \"Best solution is probably Bd2\"; id \"WAC.287\";", "r1b2rk1/p4ppp/1p1Qp3/4P2N/1P6/8/P3qPPP/3R1RK1 w - - bm Nf6+; id \"WAC.288\";", "2r3k1/5p1p/p3q1p1/2n3P1/1p1QP2P/1P4N1/PK6/2R5 b - - bm Qe5; id \"WAC.289\";", "2k2r2/2p5/1pq5/p1p1n3/P1P2n1B/1R4Pp/2QR4/6K1 b - - bm Ne2+; id \"WAC.290\";", "5r1k/3b2p1/p6p/1pRpR3/1P1P2q1/P4pP1/5QnP/1B4K1 w - - bm h3; id \"WAC.291\";", "4r3/1Q1qk2p/p4pp1/3Pb3/P7/6PP/5P2/4R1K1 w - - bm d6+; id \"WAC.292\";", "1nbq1r1k/3rbp1p/p1p1pp1Q/1p6/P1pPN3/5NP1/1P2PPBP/R4RK1 w - - bm Nfg5; id \"WAC.293\";", "3r3k/1r3p1p/p1pB1p2/8/p1qNP1Q1/P6P/1P4P1/3R3K w - - bm Bf8 Nf5 Qf4; id \"WAC.294\";", "4r3/p4r1p/R1p2pp1/1p1bk3/4pNPP/2P1K3/2P2P2/3R4 w - - bm Rxd5+; id \"WAC.295\";", "3r4/1p2k2p/p1b1p1p1/4Q1Pn/2B3KP/4pP2/PP2R1N1/6q1 b - - bm Rd4+ Rf8; id \"WAC.296\";", "3r1rk1/p3qp1p/2bb2p1/2p5/3P4/1P6/PBQN1PPP/2R2RK1 b - - bm Bxg2 Bxh2+; id \"WAC.297\";", "3Q4/p3b1k1/2p2rPp/2q5/4B3/P2P4/7P/6RK w - - bm Qh8+; id \"WAC.298\";", "1n2rr2/1pk3pp/pNn2p2/2N1p3/8/6P1/PP2PPKP/2RR4 w - - bm Nca4; id \"WAC.299\";", "b2b1r1k/3R1ppp/4qP2/4p1PQ/4P3/5B2/4N1K1/8 w - - bm g6; id \"WAC.300\";", NULL }; static const char *sts_test[] = { "1kr5/3n4/q3p2p/p2n2p1/PppB1P2/5BP1/1P2Q2P/3R2K1 w - - bm f5; id \"Undermine.001\"; c0 \"f5=10, Be5+=2, Bf2=3, Bg4=2\";", "1n5k/3q3p/pp1p2pB/5r2/1PP1Qp2/P6P/6P1/2R3K1 w - - bm c5; id \"Undermine.002\"; c0 \"c5=10, Qd4+=4, b5=4, g4=3\";", "1n6/4bk1r/1p2rp2/pP2pN1p/K1P1N2P/8/P5R1/3R4 w - - bm c5; id \"Undermine.003\"; c0 \"c5=10, Rd3=7, Rdd2=7, Rg3=7 Rd5=9\";", "1nr5/1k5r/p3pqp1/3p4/1P1P1PP1/R4N2/3Q1PK1/R7 w - - bm b5; id \"Undermine.004\"; c0 \"b5=10, Kg3=4, Ng5=4, Qe3=4\";", "1q2r1k1/1b2bpp1/p2ppn1p/2p5/P3PP1B/2PB1RP1/2P1Q2P/2KR4 b - - bm c4; id \"Undermine.005\"; c0 \"c4=10, Bc6=7, Qa8=7, Qc8=7\";", "1q4k1/5p1p/p1rprnp1/3R4/N1P1P3/1P6/P5PP/3Q1R1K w - - bm e5; id \"Undermine.006\"; c0 \"e5=10, Nc3=3, Qd3=1, Qf3=2\";", "1qr1k2r/1p2bp2/pBn1p3/P2pPbpp/5P2/2P1QBPP/1P1N3R/R4K2 b k - bm h4; id \"Undermine.007\"; c0 \"h4=10, Bd8=1, Bf8=1, Rh7=1\";", "1r1b2k1/2r2ppp/p1qp4/3R1NPP/1pn1PQB1/8/PPP3R1/1K6 w - - bm g6; id \"Undermine.008\"; c0 \"g6=10, Ka1=2, Nd4=2, Rd3=2\";", "1r1qk1nr/p3ppbp/3p2p1/1pp5/2bPP3/4B1P1/2PQNPBP/R2R2K1 w k - bm e5; id \"Undermine.009\"; c0 \"e5=10, Bf3=5, Nc1=5, Rxa7=4\";", "1r1r2k1/p3n2p/b1nqpbp1/2pp4/1p3PP1/2PP1N2/PPN3BP/R1BRQ2K w - - bm d4; id \"Undermine.010\"; c0 \"d4=10, Ng5=6, a4=6, h3=6\";", "1r2n1rk/pP2q2p/P2p4/4pQ2/2P2p2/5B1P/3R1P1K/3R4 w - - bm c5; id \"Undermine.011\"; c0 \"c5=10, Bc6=6, Qc2=5, Rg1=5\";", "1r3bk1/7p/pp1q2p1/P1pPp3/2P3b1/4B3/1P1Q2BP/R6K w - - bm b4; id \"Undermine.012\"; c0 \"b4=10, Bg1=3, axb6=3, h3=1\";", "1r3rk1/3n1pbp/1q1pp1p1/p1p5/2PnPP2/PPB1N1PP/6B1/1R1Q1RK1 b - - bm a4; id \"Undermine.013\"; c0 \"a4=10, Ne2+=2, Rfd8=2, h5=2\";", "1r3rk1/p5bp/6p1/q1pPppn1/7P/1B1PQ1P1/PB3P2/R4RK1 b - - bm f4; id \"Undermine.014\"; c0 \"f4=10, Nf7=4, c4=5, e4=5\";", "1r4k1/1rq2pp1/3b1nn1/pBpPp3/P1N4p/2PP1Q1P/6PB/2R2RK1 w - - bm d4; id \"Undermine.015\"; c0 \"d4=10, Bc6=4, Qf5=6, Rce1=4\";", "1r4k1/p1rqbp1p/b1p1p1p1/NpP1P3/3PB3/3Q2P1/P4P1P/3RR1K1 w - - bm a4; id \"Undermine.016\"; c0 \"a4=10, Kg2=4, Qf3=4, h4=5\";", "2r3k1/p2q1pp1/Pbrp3p/6n1/1BP1PpP1/R4P2/2QN2KP/1R6 b - - bm h5; id \"Undermine.017\"; c0 \"h5=10, Be3=4, Ne6=4, Qd8=4\";", "1r6/2q2pk1/2n1p1pp/p1Pr4/P1RP4/1p1RQ2P/1N3PP1/7K b - - bm e5; id \"Undermine.018\"; c0 \"e5=10, Kh7=4, Qb7=5, Rbd8=5\";", "1r6/R1nk1p2/1p4pp/pP1p1P2/P2P3P/5PN1/5K2/8 w - - bm h5; id \"Undermine.019\"; c0 \"h5=10, Ne2=4, Nf1=7, f4=7\";", "1rb3k1/2pn2pp/p2p4/4p3/1pP4q/1P1PBP1P/1PQ2P2/R3R1K1 w - - bm c5; id \"Undermine.020\"; c0 \"c5=10, Kf1=5, Kg2=5, Ra5=5\";", "1rbqnrk1/6bp/pp3np1/2pPp3/P1P1N3/2N1B3/1P2Q1BP/R4R1K w - - bm a5; id \"Undermine.021\"; c0 \"a5=10, Bg5=6, Kg1=6, Nxf6+=6\";", "1rr3k1/1q3pp1/pnbQp2p/1p2P3/3B1P2/2PB4/P1P2RPP/R5K1 w - - bm f5; id \"Undermine.022\"; c0 \"f5=10, Qa3=3, Rd1=2, h3=2\";", "2kr2r1/1bpnqp2/1p1ppn2/p5pp/P1PP4/4PP2/1P1NBBPP/R2Q1RK1 w - - bm b4; id \"Undermine.023\"; c0 \"b4=10, Qb1=3, Qc2=4, Re1=4\";", "2b1k2r/5p2/pq1pNp1b/1p6/2r1PPBp/3Q4/PPP3PP/1K1RR3 w k - bm e5; id \"Undermine.024\"; c0 \"e5=10, Qd5=1, Qh3=7, f5=1\";", "2b1r1k1/1p6/pQ1p1q1p/P2P3P/2P1pPpN/6P1/4R1K1/8 w - - bm c5; id \"Undermine.025\"; c0 \"c5=10, Kg1=6, Kh2=5, Re3=5\";", "2b2rk1/2qn1p2/p2p2pp/2pPP3/8/4NN1P/P1Q2PP1/bB2R1K1 w - - bm e6; id \"Undermine.026\"; c0 \"e6=10, Nc4=1, Ng4=1, exd6=2\";", "2bq2k1/1pr3bp/1Qpr2p1/P2pNp2/3P1P1P/6P1/5PB1/1RR3K1 w - - bm a6; id \"Undermine.027\"; c0 \"a6=10, Qc5=2, Rc5=3, h5=2\";", "rr6/8/2pbkp2/ppp1p1p1/P3P3/1P1P1PB1/R1P2PK1/R7 b - - bm c4; id \"Undermine.28\"; c0 \"c4=10, Bc7=4, Rb6=1, b4=1\";", "2r2rk1/pb2q2p/1pn1p2p/5p1Q/3P4/P1NB4/1P3PPP/R4RK1 w - - bm d5; id \"Undermine.029\"; c0 \"d5=10, Qxh6=5, Rac1=5, Rfd1=5\";", "2kr4/ppqnbp1r/2n1p1p1/P2pP3/3P2P1/3BBN2/1P1Q1PP1/R4RK1 w - - bm a6; id \"Undermine.030\"; c0 \"a6=10, Qc2=3, Rfc1=4, g3=4\";", "2q5/1pb2r1k/p1b3pB/P1Pp3p/3P4/3B1pPP/1R3P1K/2Q5 b - - bm h4; id \"Undermine.031\"; c0 \"h4=10, Bb5=5, Bd7=1, Qd8=5\";", "2r1kb1r/1bqn1pp1/p3p3/1p2P1P1/3Np3/P1N1B3/1PP1Q2P/R4RK1 w k - bm g6; id \"Undermine.032\"; c0 \"g6=10, Bf4=6, Rae1=6, Rf4=6\";", "2r1rb2/1bq2p1k/3p1np1/p1p5/1pP1P1P1/PP2BPN1/2Q3P1/R2R1BK1 b - - bm d5; id \"Undermine.033\"; c0 \"d5=10, Bg7=7, Kg8=7, Nd7=7\";", "2r2bk1/pq3r1p/6p1/2ppP1P1/P7/BP1Q4/2R3P1/3R3K b - - bm d4; id \"Undermine.034\"; c0 \"d4=10, Qe7=1, Rcc7=1, c4=1\";", "2r2rk1/1bb2ppp/p2ppn2/1p4q1/1PnNP3/P1N4P/2P1QPPB/3RRBK1 w - - bm a4; id \"Undermine.035\"; c0 \"a4=10, Nf3=4, Rb1=5, Rd3=5\";", "2r2rk1/3q3p/p3pbp1/1p1pp3/4P3/2P5/PPN1QPPP/3R1RK1 b - - bm d4; id \"Undermine.036\"; c0 \"d4=10, Bg7=7, Qb7=6, Qd6=7\";", "2r4k/pp3q1b/5PpQ/3p4/3Bp3/1P6/P5RP/6K1 w - - bm h4; id \"Undermine.037\"; c0 \"h4=10, Rg3=2, Rg4=2, Rg5=2\";", "2r3k1/1b2b2p/r2p1pp1/pN1Pn3/1pPB2P1/1P5P/P3R1B1/5RK1 w - - bm g5; id \"Undermine.038\"; c0 \"g5=10, Rd1=4, Rff2=4, h4=5\";", "2r3k1/5pp1/1pq4p/p7/P1nR4/2P2P2/Q5PP/4B1K1 b - - bm b5; id \"Undermine.039\"; c0 \"b5=10, Nd6=1, Ne3=1, Ne5=1\";", "6k1/6pp/4r3/p1qpp3/Pp6/1n1P1B1P/1B2Q1P1/3R1K2 w - - bm d4; id \"Undermine.040\"; c0 \"d4=10, Bxe5=3, Qf2=2, Re1=3\";", "r2qkb1r/1b1n1ppp/p3pn2/1pp5/3PP3/2NB1N2/PP3PPP/R1BQ1RK1 w kq - bm d5; id \"Undermine.041\"; c0 \"d5=10, Be3=3, a3=2, e5=3\";", "r3r1k1/pn1bnpp1/1p2p2p/1q1pPP2/1BpP3N/2P2BP1/2P3QP/R4RK1 w - - bm f6; id \"Undermine.42\"; c0 \"f6=10, Bxe7=6, Rab1=5, g4=5\";", "2r5/p3kpp1/1pn1p2p/8/1PP2P2/PB1R1KP1/7P/8 b - - bm a5; id \"Undermine.043\"; c0 \"a5=10, a6=1, e5=1, f5=1\";", "2rq1rk1/1b2bppp/p2p1n2/1p1Pp3/1Pn1P3/5N1P/P1B2PP1/RNBQR1K1 w - - bm a4; id \"Undermine.044\"; c0 \"a4=10, Bb3=1, Nbd2=1, Nc3=1\";", "2rqr1k1/1b2bp1p/ppn1p1pB/3n4/3P3P/P1NQ1N2/1PB2PP1/3RR1K1 w - - bm h5; id \"Undermine.045\"; c0 \"h5=10, Bc1=4, Nxd5=1, Rb1=1\";", "3Rb3/5ppk/2r1r3/p5Pp/1pN2P1P/1P5q/P4Q2/K2R4 b - - bm a4; id \"Undermine.046\"; c0 \"a4=10, Rc7=7, Re7=6, Rxc4=7\";", "3Rbrk1/4Q2p/6q1/pp3p2/4p2P/1P4P1/8/5R1K w - - bm g4; id \"Undermine.047\"; c0 \"g4=10, Kh2=5, Rc8=2, Rf2=3\";", "3bn3/3r1p1k/3Pp1p1/1q6/Np2BP1P/3R2PK/8/3Q4 w - - bm h5; id \"Undermine.048\"; c0 \"h5=10, Bf3=6, Rd4=6, g4=6\";", "3k1r1r/p2n1p1p/q2p2pQ/1p2P3/2pP4/P4N2/5PPP/2R1R1K1 w - - bm a4; id \"Undermine.049\"; c0 \"a4=10, Ng5=5, Qh4+=8, exd6=6\";", "3r1bk1/1p2qp1p/p5p1/P1pPp3/2QnP3/3BB3/1P3PPP/2R3K1 w - - bm f4; id \"Undermine.050\"; c0 \"f4=10, Rb1=4, Rf1=4, h3=4\";", "3r1bkr/2q3pp/1p1Npp2/pPn1P3/5B2/1P6/2P2PPP/R2QR1K1 w - - bm b4; id \"Undermine.051\"; c0 \"b4=10, Bd2=5, Qf3=4, exf6=3\";", "3r2k1/p2q1pp1/1p2n1p1/2p1P2n/P4P2/2B1Q1P1/7P/1R3BK1 w - - bm a5; id \"Undermine.052\"; c0 \"a5=10, Bb5=3, Qe4=1, Ra1=3\";", "3r4/8/pq3kr1/3Bp3/7p/1P3P2/P5PP/3RQ2K b - - bm h3; id \"Undermine.053\"; c0 \"h3=10, Kg7=5, Rd7=4, Rh6=5\";", "3r4/pk1p3p/1p2pp2/1N6/2P1KP2/6P1/3R3P/8 w - - bm f5; id \"Undermine.054\"; c0 \"f5=10, Kd4=5, Ke3=5, Nc3=5\";", "4k2r/1b2b3/p3pp1p/1p1p4/3BnpP1/P1P4R/1KP4P/5BR1 w k - bm g5; id \"Undermine.055\"; c0 \"g5=10, Be2=5, a4=6, c4=5\";", "4k3/r2bbprp/3p1p1N/2qBpP2/ppP1P1P1/1P1R3P/P7/1KR1Q3 w - - bm a3; id \"Undermine.056\"; c0 \"a3=10, Qd2=3, Rc2=3, h4=3\";", "4q1k1/pb5p/Nbp1p1r1/3r1p2/PP1Pp1pP/4P1P1/1BR1QP2/2R3K1 w - - bm b5; id \"Undermine.057\"; c0 \"b5=10, Ba1=3, Kg2=3, a5=3\";", "4r1k1/1pb3qp/p1b1r1p1/P1Pp4/3P1p2/2BB4/1R1Q1PPP/1R4K1 b - - bm f3; id \"Undermine.058\"; c0 \"f3=10, Qd7=7, Qe7=7, Qf6=7\";", "4r1k1/5p1p/p2q2p1/3p4/3Qn3/2P1RN2/Pr3PPP/R5K1 w - - bm c4; id \"Undermine.059\"; c0 \"c4=10, Ree1=5, a3=5, g3=5\";", "4rr1k/pp1n2bp/7n/1Pp1pp1q/2Pp3N/1N1P1PP1/P5QP/2B1RR1K b - - bm f4; id \"Undermine.060\"; c0 \"f4=10, Nf7=3, Rf7=4, b6=1\";", "4rrk1/p6p/2q2pp1/1p6/2pP1BQP/5N2/P4PP1/2R3K1 w - - bm h5; id \"Undermine.061\"; c0 \"h5=10, Bd2=1, Qg3=1, a4=1\";", "5nk1/1bp1rnp1/pp1p4/4p1P1/2PPP3/NBP5/P2B4/4R1K1 w - - bm c5; id \"Undermine.062\"; c0 \"c5=10, Kf1=7, Kf2=7, d5=7\";", "5r2/1p1k4/2bp4/r3pp1p/PRP4P/2P2PP1/2B2K2/7R b - - bm f4; id \"Undermine.063\"; c0 \"f4=10, Kc7=4, Raa8=4, Rf7=4\";", "5r2/5p1Q/4pkp1/p7/1pb2q1P/5P2/P4RP1/3R2K1 w - - bm h5; id \"Undermine.064\"; c0 \"h5=10, Rb2=1, Rd7=1, Rdd2=1\";", "5rk1/1Q3pp1/p2p3p/4p1b1/N3PqP1/1N1K4/PP6/3R4 b - - bm d5; id \"Undermine.065\"; c0 \"d5=10, Qf3+=1, Qxg4=1, h5=1\";", "7r/3nkpp1/4p3/p1pbP3/1r3P1p/1P2B2P/P2RBKP1/7R b - - bm a4; id \"Undermine.066\"; c0 \"a4=10, Rc8=6, Rd8=6, Rhb8=6\";", "8/1r1rq2k/2p3p1/3b1p1p/4p2P/1N1nP1P1/2Q2PK1/RR3B2 b - - bm f4; id \"Undermine.067\"; c0 \"f4=10, Rb4=3, c5=3, g5=3\";", "8/1r2k3/4p2p/R3K2P/1p1P1P2/1P6/8/8 w - - bm f5; id \"Undermine.068\"; c0 \"f5=10, Ke4=4, Rc5=4, d5=3\";", "8/3r1pp1/p7/2k2PpP/rp1pB3/2pK1P2/P1R5/1R6 w - - bm f6; id \"Undermine.069\"; c0 \"f6=10, Rg1=1, Rh1=1, f4=2\";", "8/6k1/3P1bp1/2B1p3/1P6/1Q3P1q/7r/1K2R3 b - - bm e4; id \"Undermine.070\"; c0 \"e4=10, Qc8=1, Qf5+=1, g5=1\";", "b2rrbk1/2q2p1p/pn1p2p1/1p4P1/2nNPB1P/P1N3Q1/1PP3B1/1K1RR3 w - - bm h5; id \"Undermine.071\"; c0 \"h5=10, Bc1=6, Na2=6, Qh3=6\";", "b7/2pr1kp1/1p3p2/p2p3p/P1nP1N2/4P1P1/P1R2P1P/2R3K1 w - - bm e4; id \"Undermine.072\"; c0 \"e4=10, Rc3=5, Re2=6, f3=5\";", "k1qbr1n1/1p4p1/p1p1p1Np/2P2p1P/3P4/R7/PP2Q1P1/1K1R4 w - - bm d5; id \"Undermine.073\"; c0 \"d5=10, Ra4=3, Rdd3=4, g4=3\";", "r1b1rnk1/pp3pq1/2p3p1/6P1/2B2P1R/2P5/PP1Q2P1/2K4R w - - bm f5; id \"Undermine.074\"; c0 \"f5=10, Bd3=3, Rh8+=1, g4=4\";", "r1bq1rk1/pp3pbp/3Pp1p1/2p5/4PP2/2P5/P2QB1PP/1RB1K2R b K - bm e5; id \"Undermine.075\"; c0 \"e5=10, Bd7=7, Qh4+=7, b6=6\";", "r1bqr2k/pppn2bp/4n3/2P1p1p1/1P2Pp2/5NPB/PBQN1P1P/R4RK1 w - - bm c6; id \"Undermine.076\"; c0 \"c6=10, Nb3=5, Nc4=5, Rac1=5\";", "r1br1k2/1pq2pb1/1np1p1pp/2N1N3/p2P1P1P/P3P1R1/1PQ3P1/1BR3K1 w - - bm h5; id \"Undermine.077\"; c0 \"h5=10, Ba2=4, Re1=4, Rf1=5\";", "r1n2k1r/5pp1/2R5/pB2pPq1/P2pP3/6Pp/1P2Q2P/5RK1 w - - bm f6; id \"Undermine.078\"; c0 \"f6=10, Qd3=2, Rc5=2, Rg6=2\";", "r1r2bk1/pp1n1p1p/2pqb1p1/3p4/1P1P4/1QN1PN2/P3BPPP/2RR2K1 w - - bm b5; id \"Undermine.079\"; c0 \"b5=10, Qc2=5, Rb1=4, a3=4\";", "r2q1r2/pp1b2kp/2n1p1p1/3p4/3P1P1P/2PB1N2/6P1/R3QRK1 w - - bm h5; id \"Undermine.080\"; c0 \"h5=10, Qe3=3, Rb1=4, g3=4\";", "r2q1rk1/pp2b1pp/1np1b3/4pp2/1P6/P1NP1BP1/2Q1PP1P/1RB2RK1 w - - bm b5; id \"Undermine.081\"; c0 \"b5=10, Be3=1, Bg2=1, Re1=1\";", "r2q4/6k1/r1p3p1/np1p1p2/3P4/4P1P1/R2QBPK1/7R w - - bm e4; id \"Undermine.082\"; c0 \"e4=10, Qb2=5, Qc3=5, Rc2=2\";", "r2qr1k1/pp3pbp/5np1/2p2b2/8/2PP1Q2/PPB3PP/RNB2RK1 b - - bm c4; id \"Undermine.083\"; c0 \"c4=10, Bg4=3, Ng4=2, Qd7=3\";", "r3k2r/1bq1bpp1/p4n2/2p1pP2/2NpP2p/3B4/PPP3PP/R1B1QR1K b k - bm h3; id \"Undermine.084\"; c0 \"h3=10, Bc6=3, Bd8=1, Kf8=1\";", "r3k2r/2q2p2/p2bpPpp/1b1p4/1p1B1PPP/8/PPPQ4/1K1R1B1R w kq - bm f5; id \"Undermine.085\"; c0 \"f5=10, Be3=6, Bxb5+=4, h5=4\";", "r3k2r/ppq2p1p/2n1p1p1/3pP3/5PP1/2P1Q3/PP2N2P/3R1RK1 b k - bm h5; id \"Undermine.086\"; c0 \"h5=10, O-O=3, Qb6=1, Rc8=1, Rc8=3\";", "r3r1k1/1pp1np1p/1b1p1p2/pP2p3/2PP2b1/P3PN2/1B3PPP/R3KB1R w KQ - bm c5; id \"Undermine.087\"; c0 \"c5=10, Be2=3, Rd1=3, dxe5=3\";", "r3r1k1/1pq2pbp/p1ppbnp1/4n3/2P1PB2/1NN2P2/PP1Q2PP/R3RBK1 w - - bm c5; id \"Undermine.088\"; c0 \"c5=10, Bxe5=7, Nd1=7, Red1=7\";", "r3r1k1/bpp1np1p/3p1p2/pPP1p3/3P2b1/P3PN2/1B3PPP/R3KB1R w KQ - bm b6; id \"Undermine.089\"; c0 \"b6=10, Rc1=3, Rd1=2, h3=5\";", "r3r1k1/pp2q3/2b1pp2/6pN/Pn1P4/6R1/1P3PP1/3QRBK1 w - - bm f4; id \"Undermine.090\"; c0 \"f4=10, Qd2=4, b3=5, f3=3\";", "r4r2/1p2pbk1/1np1qppp/p7/3PP2P/P1Q2NP1/1P3PB1/2R1R1K1 w - - bm h5; id \"Undermine.091\"; c0 \"h5=10, Qc5=5, Qe3=3, b4=2\";", "r4r2/2p2kb1/1p1p2p1/qPnPp2n/2B1PP2/pP6/P1Q1N2R/1KB4R w - - bm f5; id \"Undermine.092\"; c0 \"f5=10, Bd2=5, Rg1=3, Rg2=4\";", "r4rk1/2p5/p2p1n2/1p1P3p/2P1p1pP/1P4B1/1P3PP1/3RR1K1 w - - bm c5; id \"Undermine.093\"; c0 \"c5=10, Rc1=5, Rd2=4, Re2=6\";", "r4rk1/2qnb1pp/4p3/ppPb1p2/3Pp3/1PB3P1/R1QNPPBP/R5K1 b - - bm a4; id \"Undermine.094\"; c0 \"a4=10, Bf6=6, Qc6=6, e5=6\";", "r4rk1/p5pp/1p2b3/2Pn1p2/P2Pp2P/4P1Pq/2Q1BP2/R1BR2K1 w - - bm a5; id \"Undermine.095\"; c0 \"a5=10, Bc4=5, Bf1=5, Rb1=6\";", "r4rk1/pbq2p2/2p2np1/1p2b2p/4P3/2N1BPP1/PPQ1B2P/R2R2K1 b - - bm h4; id \"Undermine.096\"; c0 \"h4=10, Rfd8=2, a5=3, a6=2\";", "r4rk1/pp1b2b1/n2p1nq1/2pP1p1p/2P1pP2/PP4PP/1BQ1N1B1/R3RNK1 b - - bm h4; id \"Undermine.097\"; c0 \"h4=10, Rab8=1, Rae8=1, Rf7=1\";", "rn3rk1/p1p1qp2/1pbppn1p/6p1/P1PP4/2PBP1B1/3N1P1P/R2QK1R1 w Q - bm h4; id \"Undermine.098\"; c0 \"h4=10, Qe2=1, a5=1, f4=1\";", "rnbq1rk1/2p1p1bp/p3pnp1/1p6/3P4/1QN1BN2/PP3PPP/R3KB1R w KQ - bm a4; id \"Undermine.099\"; c0 \"a4=10, Rc1=6, g3=6, h3=6\";", "rr3n1k/q3bpn1/2p1p1p1/2PpP2p/pP1P1N1P/2BB1NP1/P2Q1P2/6RK w - - bm g4; id \"Undermine.100\"; c0 \"g4=10, Kh2=4, Qc1=2, a3=3\";", "1b1r4/3rkp2/p3p2p/4q3/P5P1/2RBP3/P1Q4P/1R3K2 b - - bm Ba7; c0 \"Ba7=10, Qf6+=3, a5=3, h5=5\"; id \"STS(v2.2) Open Files and Diagonals.001\";", "1bq3rk/R6p/5n1P/1N1p4/1PnP2p1/6P1/5B2/2Q2BK1 w - - bm Re7; c0 \"Re7=10, Ra2=5, Rg7=2\"; id \"STS(v2.2) Open Files and Diagonals.002\";", "1k1r3r/1p1b1Q1p/p7/q3p3/4p3/2P1N3/P4PPP/R4RK1 w - - bm Rad1; c0 \"Rad1=10, Qf6=7, Rfd1=7, a4=2\"; id \"STS(v2.2) Open Files and Diagonals.003\";", "1Q6/1b4pk/2q2b1p/1p1ppP2/1Pp5/2P2P1P/2BB2P1/6K1 b - - bm Qa6; c0 \"Qa6=10, Bc8=5, Qd7=7\"; id \"STS(v2.2) Open Files and Diagonals.004\";", "1qrr3k/1p2bp1p/1n2p1pP/p2pP3/P4B2/1PPB2P1/2R1QP2/3R2K1 w - - bm Bb5; c0 \"Bb5=10, Qe1=2, Qe3=2\"; id \"STS(v2.2) Open Files and Diagonals.005\";", "1r1n1rk1/3qp2p/P2p2p1/1p6/5pP1/1p3P1P/5PB1/R1QR2K1 w - - bm Bf1; c0 \"Bf1=10, Qb2=7, Qc3=7, Qd2=6\"; id \"STS(v2.2) Open Files and Diagonals.006\";", "1r1n2k1/5r1p/P2qp1p1/3p4/1p3pP1/1Q3P1P/R4P2/2R2BK1 w - - bm Rac2; c0 \"Rac2=10, Kg2=5, Qa4=4\"; id \"STS(v2.2) Open Files and Diagonals.007\";", "1r1q1nk1/p3bpp1/b1p1p2p/4P3/1P2NB2/P4N2/5PPP/2Q1R1K1 w - - bm Be3; c0 \"Be3=10, Nd6=5, Rd1=7, h3=6\"; id \"STS(v2.2) Open Files and Diagonals.008\";", "1r1q4/5p2/2p4k/1n2p1pP/4P3/P4BR1/3Q1PKP/8 w - - bm Qc1; c0 \"Qc1=10, Qa2=5, Qe3=6\"; id \"STS(v2.2) Open Files and Diagonals.009\";", "1r1qbr1k/4bp1p/p3p2Q/3pP3/2pP4/P1N1PN2/1PR2RP1/6K1 b - - bm Rg8; c0 \"Rg8=10, Bc6=1, Bd7=4\"; id \"STS(v2.2) Open Files and Diagonals.010\";", "1r3k2/8/R7/4pPP1/P1p5/1nP5/R5P1/3rB1K1 w - - bm Rh6; c0 \"Rh6=10, Kf1=6, Rf6+=6\"; id \"STS(v2.2) Open Files and Diagonals.011\";", "1r3rk1/2b3pp/p4p2/2p5/P1Np4/1P1R2P1/1P3P1P/2R3K1 b - - bm Rfe8; c0 \"Rfe8=10, Rfc8=7, Rfd8=8\"; id \"STS(v2.2) Open Files and Diagonals.012\";", "1r5k/p7/3pQ1p1/1Np5/2P3P1/7P/1PK5/7q b - - bm Qf1; c0 \"Qf1=10, Qg2+=2, Qh2+=2\"; id \"STS(v2.2) Open Files and Diagonals.013\";", "1r6/4q3/2p2p1k/4p1pP/P2nP2P/5BR1/5PK1/2Q5 w - - bm Bg4; c0 \"Bg4=10, Bd1=6, a5=8\"; id \"STS(v2.2) Open Files and Diagonals.014\";", "1r6/7k/1p4r1/1P2p3/2P1p2P/2RbB3/6P1/2R4K w - - bm Ra1; c0 \"Ra1=10, Kg1=7, Kh2=8\"; id \"STS(v2.2) Open Files and Diagonals.015\";", "1r6/8/1r5p/p2pk3/4p3/2P4P/RP2B1n1/1RK5 b - - bm Rf6; c0 \"Rf6=10, Rf8=8, Rg6=6\"; id \"STS(v2.2) Open Files and Diagonals.016\";", "1rbr2k1/pp3pp1/q6p/4P3/3p1P2/6P1/P2QP1BP/R1R3K1 w - - bm Be4; c0 \"Be4=10, Bf3=4, Qd3=5\"; id \"STS(v2.2) Open Files and Diagonals.017\";", "2b1r1k1/2r5/p3pbp1/5p2/PN5P/1Pp2BP1/4PP2/2R2RK1 w - - bm Rfd1; c0 \"Rfd1=10\"; id \"STS(v2.2) Open Files and Diagonals.018\";", "2r1k3/p5pp/1p2p3/7P/P2B2Q1/1bP5/R4PPK/4q3 w - - bm Re2; c0 \"Re2=10, Qxg7=4, Rb2=4\"; id \"STS(v2.2) Open Files and Diagonals.019\";", "2r1q1k1/2p2rbp/p2p2p1/Q2P4/b3P3/3p2P1/3B1PBP/2R1R1K1 w - - bm Bh3; c0 \"Bh3=10, Bf1=7, e5=8\"; id \"STS(v2.2) Open Files and Diagonals.020\";", "2r1q2k/7p/p1np1P1P/8/1pP2R2/8/PP1Q4/R1KN2r1 b - - bm Qg6; c0 \"Qg6=10, Ne5=4, Qe5=2\"; id \"STS(v2.2) Open Files and Diagonals.021\";", "2r1q3/p1p1nk1p/4p2p/2R1Pp2/1P1Q4/P3N1P1/5P2/6K1 w - - bm Qh4; c0 \"Qh4=10, Rc1=6, Rc2=9, Rc4=6\"; id \"STS(v2.2) Open Files and Diagonals.022\";", "2r2k2/R4bpp/2p2p2/1pN5/1n3PP1/1P2P2P/8/5BK1 w - - bm Bg2; c0 \"Bg2=10, e4=6\"; id \"STS(v2.2) Open Files and Diagonals.023\";", "2r2rk1/1p1nbppp/p2p4/B2Pp1PP/5P2/1P6/P1P5/1K1R1B1R w - - bm Bh3; c0 \"Bh3=10, Bd2=5, Re1=6\"; id \"STS(v2.2) Open Files and Diagonals.024\";", "2r2rk1/4q1pp/p7/1pb1Pp2/5P2/1P1QB3/b3N1PP/2R1K2R b K - bm Rfd8; c0 \"Rfd8=10, Bxe3=5, Kh8=3\"; id \"STS(v2.2) Open Files and Diagonals.025\";", "2r3k1/1b1n1npp/1pq2p2/8/1P1QP3/6P1/1B1NBP1P/3R2K1 w - - bm Rc1; c0 \"Rc1=10, Bg4=7, f3=7, f4=5\"; id \"STS(v2.2) Open Files and Diagonals.026\";", "2r3n1/p1p3kp/1q2p2p/4Pp2/1P4N1/P5P1/1Q3P2/2R3K1 w - - bm Qd2; c0 \"Qd2=10, Ne3=9, Nf6=5\"; id \"STS(v2.2) Open Files and Diagonals.027\";", "2rq2k1/1p3pb1/1n4pp/pP2p3/P1b1P3/2N4P/2B1NPP1/R1Q3K1 b - - bm Bf8; c0 \"Bg7f8=10, Bg7f6=8, Qd8d6=7\"; id \"STS(v2.2) Open Files and Diagonals.028\";", "2rq2k1/4rpp1/p3p3/P2n2pP/2pPR3/2P3B1/2Q2PP1/R5K1 b - - bm Rb7; c0 \"Rb7=10, Ra7=4, Rd7=3\"; id \"STS(v2.2) Open Files and Diagonals.029\";", "2rr1b2/3q3k/p4n1p/1p1p2p1/2nNp3/P1N2PQ1/1PP3PP/R1BR2K1 b - - bm Bd6; c0 \"Bd6=10, Bc5=7, Bg7=5\"; id \"STS(v2.2) Open Files and Diagonals.030\";", "3b2k1/1p1b4/4p2B/1n1p1p2/pN6/P2P4/1PR3PP/7K w - - bm Be3; c0 \"Be3=10, Bf4=7, Re2=7\"; id \"STS(v2.2) Open Files and Diagonals.031\";", "3q2k1/5rpp/r1pPp3/1bQn4/p2B4/4P1P1/1P1R2BP/R5K1 w - - bm Bh3; c0 \"Bh3=10, Rc1=8, Rc2=7\"; id \"STS(v2.2) Open Files and Diagonals.032\";", "3Q4/5pk1/4p1p1/3pb2p/P3q2P/1r4P1/2R2P1K/2R5 b - - bm Bf4; c0 \"Bf4=10, Ra3=3, Rd3=4\"; id \"STS(v2.2) Open Files and Diagonals.033\";", "3q4/7k/3ppp2/p3n2B/P1r1P2P/8/1PPQ4/1K3R2 w - - bm Rg1; c0 \"Rg1=10, Qe3=7, Qg2=5\"; id \"STS(v2.2) Open Files and Diagonals.034\";", "3r1k2/R4bpp/2p2p2/1pN5/1n3PP1/1P2P2P/6B1/6K1 w - - bm Be4; c0 \"Be4=10, Bf3=2, g5=3\"; id \"STS(v2.2) Open Files and Diagonals.035\";", "3r1r2/p5k1/1pnpP2p/6p1/2P3P1/4P3/P1B1K1P1/3R3R w - - bm Ba4; c0 \"Ba4=10, Rdf1=6, Rhf1=7\"; id \"STS(v2.2) Open Files and Diagonals.036\";", "3r2k1/4q1pp/p7/1p2Pp2/5P2/1P2Q3/b5PP/2N1K2R b K - bm Bb1; c0 \"Bb1=10\"; id \"STS(v2.2) Open Files and Diagonals.037\";", "3r2k1/pp1q1ppp/4rnn1/3p4/P1pP4/2P1P2P/1BQN1PP1/RR4K1 w - - bm Ba3; c0 \"Ba3=10, Qd1=4, Qf5=4\"; id \"STS(v2.2) Open Files and Diagonals.038\";", "3r2k1/R7/1p3np1/1P1b4/1p6/5PqP/2Q3P1/3R2K1 b - - bm Re8; c0 \"Re8=10, Rf8=4\"; id \"STS(v2.2) Open Files and Diagonals.039\";", "3r3k/1p2R2p/pP4p1/8/2rp1p2/5P2/2P3PP/4R1K1 w - - bm Rc7; c0 \"Rc7=10\"; id \"STS(v2.2) Open Files and Diagonals.040\";", "3r4/3pkpp1/4p3/2p3q1/6r1/1P6/P5B1/2R1RQK1 b - - bm Rh8; c0 \"Rh8=10, Ra8=1, f5=1\"; id \"STS(v2.2) Open Files and Diagonals.041\";", "3r4/3q2bk/3rp1p1/1p5p/4QP2/R1Pp2P1/P2B1R1P/6K1 b - - bm Rc8; c0 \"Rc8=10, Rc6=6, Re8=6\"; id \"STS(v2.2) Open Files and Diagonals.042\";", "3r4/p2rppk1/2R3p1/4q3/3b4/PP4P1/2QRNP2/5K2 b - - bm Qh5; c0 \"Qh5=10, Bb6=2, Qd5=2\"; id \"STS(v2.2) Open Files and Diagonals.043\";", "3rr1k1/1p2bppp/p1p5/P2P3q/2B1PPb1/1P1R4/3B1QP1/4R1K1 w - - bm Bc3; c0 \"Bc3=10, b4=8, f5=4\"; id \"STS(v2.2) Open Files and Diagonals.044\";", "3rr1k1/pp2q1bp/n1p1P1p1/5p2/P2N1Pb1/1BP5/6PP/R1B1QRK1 w - - bm Ba3; c0 \"Ba3=10, Ra2=5, h3=5\"; id \"STS(v2.2) Open Files and Diagonals.045\";", "4b2k/1q2bprp/pr6/3pP3/2pP4/P4N2/1P3RPQ/3N1RK1 b - - bm Bd7; c0 \"Bd7=10, Bd8=8, Rg8=1\"; id \"STS(v2.2) Open Files and Diagonals.046\";", "4k2r/p2n3p/4q1pQ/1p2b2P/8/P1P2R2/1P4P1/K4R2 w - - bm Rd1; c0 \"Rd1=10, Re1=9, Re3=5\"; id \"STS(v2.2) Open Files and Diagonals.047\";", "4qrk1/pb4p1/2p1p2p/PpP1Pr2/1P2QP1R/2B3P1/6R1/6K1 w - - bm Rd2; c0 \"Rd2=10, Be1=9, Ra2=9\"; id \"STS(v2.2) Open Files and Diagonals.048\";", "4r1k1/3q1ppb/2p5/2Pp1P1p/p2P3P/P3P1PB/5Q1K/4R3 w - - bm Rb1; c0 \"Rb1=10, Qf4=5, Re2=2, Re2=5\"; id \"STS(v2.2) Open Files and Diagonals.049\";", "4r1k1/pbq2rpp/1p2p3/4P2P/P1p4Q/1nP1B3/R1B2PP1/1R4K1 w - - bm Bg6; c0 \"Bg6=10, Qg5=1, Rd1=3, a5=4\"; id \"STS(v2.2) Open Files and Diagonals.050\";", "4r1k1/R5p1/4b2p/1p2P3/7P/P1nP4/6PK/4R3 w - - bm Rc1; c0 \"Rc1=10, Ra6=7, d4=6\"; id \"STS(v2.2) Open Files and Diagonals.051\";", "4r2k/1pp1n1pp/pb3r2/6Nq/P2P4/2PQ2P1/1R3RKP/2B5 w - - bm Rbe2; c0 \"Rbe2=10, Rf3=4, Rxf6=3, a5=3, h3=4, h4=3\"; id \"STS(v2.2) Open Files and Diagonals.052\";", "4rrk1/1b3pp1/1q3b1p/p2p1P2/3N4/2P3N1/1P3QPP/1R3R1K b - - bm Ba6; c0 \"Ba6=10\"; id \"STS(v2.2) Open Files and Diagonals.053\";", "5b2/1p1q3n/pB1p2k1/P4N1p/6pP/4R3/6P1/5RK1 w - - bm Bd4; c0 \"Bd4=10\"; id \"STS(v2.2) Open Files and Diagonals.054\";", "5k2/ppQbbp1p/8/5p2/P7/1P6/4KPPP/q4B1R b - - bm Bb4; c0 \"Bb4=10, Qa2+=2, Qb2+=2\"; id \"STS(v2.2) Open Files and Diagonals.055\";", "5r1k/6p1/p1n1pr1p/2P1p2q/P5RN/4Q2P/5PP1/2R4K w - - bm Rb1; c0 \"Rb1=10, Qd3=6, Rd1=7\"; id \"STS(v2.2) Open Files and Diagonals.056\";", "5rk1/p3qpb1/1p5p/5Q2/P7/1B2P3/1p3PPP/5RK1 b - - bm Rd8; c0 \"Rd8=10, Qb4=6, Qe5=5\"; id \"STS(v2.2) Open Files and Diagonals.057\";", "5rk1/p7/1n1q1p2/1Prp1pNp/8/5NPP/P2Q1PB1/5RK1 w - - bm Re1; c0 \"Re1=10, Qe3=4, a4=3\"; id \"STS(v2.2) Open Files and Diagonals.058\";", "5rk1/pp4p1/5rnp/3p1b2/2p2P2/P1P3P1/2P1B2P/R1B1R1K1 w - - bm Bf3; c0 \"Bf3=10, Bd1=2, Be3=7\"; id \"STS(v2.2) Open Files and Diagonals.059\";", "5rrk/pR4p1/3p2q1/P6p/2Q1pn2/7P/1PP2PP1/R3N1K1 w - - bm Ra3; c0 \"Ra3=10, Kh2=6, Rb3=4\"; id \"STS(v2.2) Open Files and Diagonals.060\";", "6k1/1b3p2/p2q2p1/P2Pp2p/1p2Pb1P/1Br5/Q4PP1/3RN1K1 b - - bm Bc8; c0 \"Bc8=10\"; id \"STS(v2.2) Open Files and Diagonals.061\";", "6k1/1q3rpp/5n2/Rp2r3/4p3/1B5P/3BQPP1/6K1 w - - bm Be3; c0 \"Be3=10, Bc3=5, g3=5\"; id \"STS(v2.2) Open Files and Diagonals.062\";", "6k1/1q5p/5np1/pb1pNp2/3P1B1P/1Q6/1P2PP2/6K1 w - - bm Qa3; c0 \"Qa3=10, Qa2=6, Qc3=7\"; id \"STS(v2.2) Open Files and Diagonals.063\";", "6k1/2q4p/r3b1p1/2P1p3/r7/4QP2/p1RN2PP/R5K1 b - - bm Rb4; c0 \"Rb4=10, R6a5=8, Ra8=8\"; id \"STS(v2.2) Open Files and Diagonals.064\";", "6k1/pb4p1/1p1b2q1/1P1p3p/3Pn3/P1r2N1P/4QPB1/2B1R1K1 b - - bm Bc8; c0 \"Bc8=10, Bb8=5, Rc4=7\"; id \"STS(v2.2) Open Files and Diagonals.065\";", "6k1/q4p2/2b1p2p/4Pp2/pP3N2/Q4PP1/6KP/8 b - - bm Qd4; c0 \"Qd4=10, Bb5=9, Qb8=6\"; id \"STS(v2.2) Open Files and Diagonals.066\";", "6r1/1R6/1bp1knp1/pp1n3p/4pP1P/1PN3B1/1P3PB1/5K2 w - - bm Bh3+; c0 \"Bh3+=10, Nxd5=6, Nxe4=6\"; id \"STS(v2.2) Open Files and Diagonals.067\";", "6r1/4bbk1/p3p1p1/Pp1pPp2/3P1P2/2P2B2/3B2K1/1R6 b - - bm Rh8; c0 \"Rh8=10, Bd8=7, Be8=7, g5=7\"; id \"STS(v2.2) Open Files and Diagonals.068\";", "6rk/1n4bp/p3R2r/1p1P1Pp1/1P6/P1pB2P1/5P2/2R3K1 b - - bm Rc8; c0 \"Rc8=10\"; id \"STS(v2.2) Open Files and Diagonals.069\";", "8/2b1rk2/2b1p1p1/5n2/p1pP2Q1/2p3P1/P4P2/2B1RK2 w - - bm Bg5; c0 \"Bg5=10, Ba3=5, Bf4=4\"; id \"STS(v2.2) Open Files and Diagonals.070\";", "8/3q1pk1/3p4/2pB2p1/P2n4/1P4BP/6P1/4R1K1 b - - bm Qf5; c0 \"Qf5=10, Kh6=3, g4=5\"; id \"STS(v2.2) Open Files and Diagonals.071\";", "8/3r1k2/2p3p1/1pPb1p2/p7/P1B2P2/4BK2/3R4 w - - bm Rh1; c0 \"Rh1=10, Bd3=5, Rd4=6\"; id \"STS(v2.2) Open Files and Diagonals.072\";", "8/5r1k/p3b1pp/4p1q1/P3Pn2/2B1N2P/3R1PPK/3Q4 w - - bm Qb1; c0 \"Qb1=10, Ba1=5, Bb2=5\"; id \"STS(v2.2) Open Files and Diagonals.073\";", "8/5r2/1pp2p1R/p3n3/4Pp1p/2P2P1k/4K2P/R7 b - - bm Rg7; c0 \"Rg7=10, b5=3\"; id \"STS(v2.2) Open Files and Diagonals.074\";", "8/p1r3kp/r3p1p1/PRp1n1P1/7R/8/4K2P/7B b - - bm Rd6; c0 \"Rd6=10, Nd7=5, Nf7=7\"; id \"STS(v2.2) Open Files and Diagonals.075\";", "8/p1rb3k/1p1b1p1p/3q1p2/1P1P4/P1n1PPP1/3N3P/R1R2Q1K b - - bm Bb5; c0 \"Bb5=10, Kg6=5, Kh8=3, h5=3\"; id \"STS(v2.2) Open Files and Diagonals.076\";", "b1r3k1/3n1pb1/p2q2p1/P2Pp2p/1p2P2P/1Rr1NN2/Q1B2PP1/3R2K1 b - - bm Bh6; c0 \"Bh6=10\"; id \"STS(v2.2) Open Files and Diagonals.077\";", "b2r4/3qk3/1p1pp3/pN4b1/P3Pp1p/2P5/4BQPP/5R1K w - - bm Bg4; c0 \"Bg4=10, Rd1=1\"; id \"STS(v2.2) Open Files and Diagonals.078\";", "q1b2k2/5ppp/2n5/P1N1n3/8/2PpB1P1/3N1P1P/R4RK1 w - - bm Rfb1; c0 \"Rfb1=10, Rfe1=7, a6=7\"; id \"STS(v2.2) Open Files and Diagonals.079\";", "r1b2r1k/1p2qpb1/1np3pp/p7/3P4/PBN2N2/1PQ2PPP/3R1RK1 w - - bm Rfe1; c0 \"Rfe1=10, Qc1=7, Qd2=6, h3=7\"; id \"STS(v2.2) Open Files and Diagonals.080\";", "r1b2rk1/4bpp1/7p/1B1pP3/3B4/8/1PP3PP/2KR3R b - - bm Bg4; c0 \"Bg4=10, Bf5=9, Ra5=8\"; id \"STS(v2.2) Open Files and Diagonals.081\";", "r1b2rk1/pp3pb1/1npN1qpp/2P5/1PBp4/P4NPP/5P2/2RQ1RK1 w - - bm Re1; c0 \"Re1=10, Nxc8=7, Qd3=7\"; id \"STS(v2.2) Open Files and Diagonals.082\";", "r1b3k1/4brp1/p6p/1p1p4/3B4/8/PPP3PP/2KR1B1R w - - bm Bd3; c0 \"Bd3=10, Be3=4, Kb1=2\"; id \"STS(v2.2) Open Files and Diagonals.083\";", "r1b3k1/pp2qrpp/1n6/1Bb1Pp2/3p1P2/7Q/PP1BN1PP/R3K2R b KQ - bm Be6; c0 \"Be6=10, a6=2\"; id \"STS(v2.2) Open Files and Diagonals.084\";", "r1b3kr/p3qpp1/1pn1p2p/3pP2P/7n/3B3Q/2P2PPN/1RB1R1K1 w - - bm Ba3; c0 \"Ba3=10, Qg3=4\"; id \"STS(v2.2) Open Files and Diagonals.085\";", "r1br2k1/p4p2/1qp4p/1p2P1p1/6n1/5NP1/PP2QN1P/R1B2BK1 b - - bm Be6; c0 \"Be6=10, Bf5=3, b4=4\"; id \"STS(v2.2) Open Files and Diagonals.086\";", "r3r1k1/1b3ppp/2p2n2/1p2b1B1/4P1B1/P6P/1PQ1NPP1/6K1 w - - bm Bf5; c0 \"Bf5=10, Bf3=3, Bxf6=3, f3=2\"; id \"STS(v2.2) Open Files and Diagonals.087\";", "r3r1k1/2q2pp1/1pp2np1/4p3/nP2P1P1/P3Q2P/3R1PB1/B1R3K1 w - - bm Bf1; c0 \"Bf1=10, Bf3=5, Rdc2=6\"; id \"STS(v2.2) Open Files and Diagonals.088\";", "r3r1k1/ppn2ppp/2p5/5P2/P7/2N4P/1PP5/R1B2RK1 w - - bm Bf4; c0 \"Bf4=10, Kg2=7, Rd1=7, f6=6\"; id \"STS(v2.2) Open Files and Diagonals.089\";", "r3r2k/2R4p/3B2b1/p7/1p2p3/6PP/PPP4K/4R3 w - - bm Bc5; c0 \"Bc5=10, c3=7, c4=7\"; id \"STS(v2.2) Open Files and Diagonals.090\";", "r4qk1/1p3rbp/3p1np1/2pPp3/b1P5/P1NBBPP1/3Q1R1P/4R1K1 w - - bm Rb1; c0 \"Rb1=10, Kg2=3, Qc1=3, Ree2=3\"; id \"STS(v2.0) Open Files and Diagonals.091\";", "r4rk1/1p2pp1p/3p1np1/q2P1P2/2P3BQ/pP5R/P1R3PP/7K w - - bm Re2; c0 \"Re2=10, Be2=2, fxg6=4\"; id \"STS(v2.2) Open Files and Diagonals.092\";", "r4rk1/1p2ppbp/1q1p2p1/p1nP1P2/2P3B1/5R2/PPRB2PP/1Q5K w - - bm Qe1; c0 \"Qe1=10, Bg5=4, Rh3=5\"; id \"STS(v2.2) Open Files and Diagonals.093\";", "r4rk1/5pb1/2p3pp/pp2n3/1n3B2/1PN1PP1P/1P2BPK1/2R3R1 w - - bm Rgd1; c0 \"Rgd1=10\"; id \"STS(v2.2) Open Files and Diagonals.094\";", "r4rk1/6b1/2p1N1p1/8/p2p3R/8/R4P1P/5K2 b - - bm Rfb8; c0 \"Rfb8=10, Rf6=6, c5=8\"; id \"STS(v2.2) Open Files and Diagonals.095\";", "r4rk1/ppp1qp1p/1n4p1/4P3/6Q1/1N6/PP3PPP/2R1R1K1 b - - bm Rad8; c0 \"Rad8=10, Nd5=5, Rfd8=6\"; id \"STS(v2.2) Open Files and Diagonals.096\";", "r5k1/p1q2pbp/Ppp1bnp1/4p1B1/Q1P1P3/2N4P/1P2BPP1/5RK1 w - - bm Rd1; c0 \"Rd1=10, Be3=1, Rc1=8, b4=1\"; id \"STS(v2.2) Open Files and Diagonals.097\";", "r5k1/p4nbp/2qN2p1/2P2p2/3p1B2/6P1/P2Q1P1P/3R2K1 w - - bm Qe2; c0 \"Qe2=10, Nxf7=8, Qd3=7\"; id \"STS(v2.2) Open Files and Diagonals.098\";", "r7/3b1pk1/6p1/3Pp2p/2P4P/p4B2/5PP1/2R3K1 b - - bm Bf5; c0 \"Bf5=10, Kf6=6, Kf8=5\"; id \"STS(v2.2) Open Files and Diagonals.099\";", "rbbrqnk1/pp3pp1/2p2n1p/5N2/3P1P2/1BN4P/PPQB2P1/R4RK1 w - - bm Rae1; c0 \"Rae1=10, Rfe1=5\"; id \"STS(v2.2) Open Files and Diagonals.100\";", "1k2r2r/1bq2p2/pn4p1/3pP3/pbpN1P1p/4QN1B/1P4PP/2RR3K b - - bm Nd7; c0 \"Nd7=10, Bc5=8, Bc6=2, Be7=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.001\";", "1q2bn2/6pk/2p1pr1p/2Q2p1P/1PP5/5N2/5PP1/4RBK1 w - - bm Ne5; c0 \"Ne5=10, Nd4=8, Ra1=6, b5=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.002\";", "1r1q1rk1/1b1n1p1p/p2b1np1/3pN3/3P1P2/P1N5/3BB1PP/1R1Q1RK1 b - - bm Ne4; c0 \"Ne4=10, Bxa3=6, Nb6=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.003\";", "1r1r1bk1/1bq2p1p/pn2p1p1/2p1P3/5P2/P1NBB3/1P3QPP/R2R2K1 b - - bm Nd5; c0 \"Nd5=10, Ba8=8, Kg7=8, a5=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.004\";", "1r1r2k1/5pp1/p2p4/1p2pnqp/1BP1Q3/PP1R2P1/5P1P/3R2K1 b - - bm Nd4; c0 \"Nd4=10, Qf6=5, bxc4=3, h4=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.005\";", "1r1r4/R3pk2/4n1p1/2p2p2/8/4B3/Pn2BPPP/5RK1 b - - bm Nd4; c0 \"Nd4=10, Nd3=1, c4=4, f4=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.006\";", "1r2k2r/pp2ppb1/2n2np1/7p/4P3/P3BB1P/1P1N1PP1/R2R2K1 b k - bm Nd7; c0 \"Nd7=10, Bh6=6, a6=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.007\";", "1r2qrk1/3bn3/pp1p3p/n1p1p1p1/P1P5/B1PP1NPP/2Q2PB1/1R2R1K1 w - - bm Nd2; c0 \"Nd2=10, Bc1=6, Qe2=9, Rb2=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.008\";", "1r2r2k/2b2q1p/p4p2/3Pn2P/3N1N2/1P2R3/4Q3/1K1R4 w - - bm Nfe6; c0 \"Nfe6=10, Ka1=4, Nf5=6, Qxa6=2, Rc3=3, h6=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.009\";", "1r3rk1/8/3p3p/p1qP2p1/R1b1P3/2Np1P2/1P1Q1RP1/6K1 w - - bm Nd1; c0 \"Nd1=10, Na2=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.010\";", "1r6/1q2b1k1/pn1pb3/B1p1p1pp/2P1Pp2/NP3P1P/1R2Q1PN/6K1 b - - bm Nc8; c0 \"Nc8=10, Bg8=8, Kg8=8, Nd7=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.011\";", "1r6/2qnrpk1/2pp1np1/pp2P3/4P3/PBN2Q2/1PPR1PP1/3R2K1 b - - bm Nxe5; c0 \"Nxe5=10, Nxe4=8, Rxe5=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.012\";", "1rr2qk1/3p1pp1/1pb2n1p/4p3/p1P1P2P/P1NQ1BP1/1P3PK1/2RR4 w - - bm Nb5; c0 \"Nb5=10, Kh2=5, Rc2=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.013\";", "2b2rk1/1r1nbppp/4p3/1p2P3/p4P2/P1N1B3/BPP4P/R2R2K1 w - - bm Ne4; c0 \"Ne4=10, Rac1=1, Rd2=3, b4=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.014\";", "2b3n1/6kp/p1nB1pp1/8/1p2P1P1/4NP2/PP3K2/3B4 w - - bm Nd5; c0 \"Nd5=10, Ba4=8, Kg3=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.015\";", "2b5/2p1r2k/1pP2q1p/p2Pp3/4R3/1PN1Q2P/P2KP3/8 w - - bm Nb5; c0 \"Nb5=10, Kc1=7, Rc4=8, h4=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.016\";", "2k3r1/1b2bp2/2p2n2/ppn1p1Bp/2p1P2P/P4B2/1P1RN1P1/4K2R b K - bm Nd3+; c0 \"Nd3+=10, Kc7=9, Ne6=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.017\";", "2r2r1k/p3ppbp/qpnp2pn/5P2/2P1PP2/P1N1BB2/1PQ3RP/3R2K1 w - - bm Nb5; c0 \"Nb5=10, Be2=8, Nd5=9, fxg6=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.018\";", "2r2rk1/4bpp1/p2pbn1p/Pp2p3/1Pq1P2N/2P4P/1BB2PP1/R2QR1K1 w - - bm Nf5; c0 \"Nf5=10, Bb1=5, Qe2=5, Qf3=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.019\";", "2r3k1/3q1pp1/ppr1p1np/4P3/P1nPQ3/5N1P/5PPK/RRB5 b - - bm Ne7; c0 \"Ne7=10, Qc7=9, Qd8=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.020\";", "2r3k1/p1r1qpb1/1p2p1p1/nR2P3/P2B4/2P5/3NQPP1/R5K1 w - - bm Ne4; c0 \"Ne4=10, Nb3=8, f4=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.021\";", "2rq1rk1/1p2b1p1/pn2p3/2p1Pn2/2pP3p/5N1P/PPQ2BP1/1BRR2K1 b - - bm Nd5; c0 \"Nd5=10, Bg5=6, Qc7=6, Qe8=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.022\";", "r7/p1r2nk1/1pNq1np1/1P1p1p2/P2Qp3/4P1P1/2R1P1BP/2R3K1 b - - bm Ng5; id \"STS(v3.1) Knight Outposts/Centralization/Repositioning.023\"; c0 \"Ng5=10, Rac8=4, Rb7=3, Re8=3\";", "2rq2k1/3nbppp/pprp1nb1/4p3/P1P1P3/1PN1BN1P/2Q1BPP1/R2R2K1 w - - bm Nh4; c0 \"Nh4=10, Ra2=5, Rab1=6, g3=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.024\";", "2rqr1k1/1p2bppp/p2p1n2/3P1P2/2Pp4/1P1B4/P3Q1PP/R1B2RK1 b - - bm Nd7; c0 \"Nd7=10, Qa5=7, h6=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.025\";", "2rr4/Bp3k1p/5pp1/8/2n3b1/P1N5/1PP2PPP/R1R3K1 w - - bm Ne4; c0 \"Ne4=10, Na4=9, f3=9, h3=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.026\";", "3R4/5pk1/2p4r/1p2p1p1/p3P1P1/P1P2P2/1P2B1K1/n7 b - - bm Nb3; c0 \"Nb3=10, Rf6=9, Rg6=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.027\";", "3q3r/2p2pk1/6p1/2p1p1Pn/1pBnP3/1P2BP1R/P5Q1/7K b - - bm Nf4; c0 \"Nf4=10, Qd7=5, c6=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.028\";", "3r1bk1/1rq2p2/2npb1p1/p3p2p/2P1P2P/1PN3P1/2N1QPBK/R2R4 w - - bm Nb5; c0 \"Nb5=10, Rdb1=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.029\";", "3r1rk1/1p4bp/2qPp1p1/p3n3/P2BN3/1PN4P/2PR2P1/4Q1K1 w - - bm Nb5; c0 \"Nb5=10, Qe3=5, Qh4=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.030\";", "3r2k1/2q2ppp/p1p1bn2/1p2b1B1/4P3/1PN2B1P/P1Q2PP1/2R4K w - - bm Nd5; c0 \"Nd5=10\"; id \"STS: Knight Outposts/Repositioning/Centralization.031\";", "3r2k1/4qpn1/R2p3p/1Pp1p1p1/1rP1P1P1/6P1/3Q1P2/4RBK1 b - - bm Ne6; c0 \"Ne6=10, Kf8=5, Kh7=4, Rd7=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.032\";", "3r4/2p2pk1/2q1n1p1/2p1p1Pn/1pB1P3/1P2BP2/P6R/4Q1K1 b - - bm Nd4; c0 \"Nd4=10, Kg8=8, Nhf4=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.033\";", "3r4/bp1r2pk/p3npqp/P2Np3/1PR1P2B/5Q1P/2P3P1/5R1K b - - bm Nd4; c0 \"Nd4=10, Bb8=4, Kh8=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.034\";", "3r4/r1pb3p/1p4kB/2p3P1/4pP2/1P2NnKP/PR3R2/8 b - - bm Nd4; c0 \"Nd4=10, Bc8=2, Bf5=2, c4=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.035\";", "3rb1k1/4qpbp/1p2p1p1/1P3n2/Q1P2p2/2N2B1P/6PK/1NR2R2 b - - bm Ne3; c0 \"Ne3=10, Bd4=3, Rb8=7, Rc8=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.036\";", "3rr1k1/1p3ppp/p1q2b2/P4P2/2P1p3/1P6/2N1Q1PP/4RR1K w - - bm Nb4; c0 \"Nb4=10, Ne3=9, Qh5=9, b4=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.037\";", "3rr1k1/pb1n1pp1/2q2b1p/2p5/2P1p2N/1P2B1P1/P1QR1PBP/3R2K1 b - - bm Ne5; c0 \"Ne5=10, Bxh4=7, Nf8=7, g6=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.038\";", "3rr3/p3b1kp/2p2pp1/1q1np3/4Q1PB/1NP5/PP3P1P/R2R2K1 b - - bm Nf4; c0 \"Nf4=10, Kf7=3, Qa6=2, a5=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.039\";", "4b1nk/p1r1p1rp/Bpq5/n3Ppp1/8/5N1P/2P2BPQ/R3R1K1 w - - bm Nd4; c0 \"Nd4=10, Bd3=5, Rad1=3, e6=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.040\";", "4k2r/1r2np2/2q1p1p1/p2pP3/n1pP1PP1/1pP1NNK1/1P2Q3/R4R2 w k - bm Ng5; c0 \"Ng5=10, Qd2=3, Qg2=3, Rf2=4, Rh1=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.041\";", "4n3/1p1b1pk1/2n5/rN4p1/1p1Np3/1B2P1P1/PP3PK1/2R5 b - - bm Ne5; c0 \"Ne5=10\"; id \"STS: Knight Outposts/Repositioning/Centralization.042\";", "4n3/1p1b1pk1/8/rNR1n1p1/1p1Np3/1B2P1P1/PP3PK1/8 b - - bm Nf3; c0 \"Nf3=10, Bxb5=3, f6=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.043\";", "4nk2/p4rr1/1pRp3b/1P1Pp2p/1P5P/2NBpP2/4R1P1/5K2 w - - bm Ne4; c0 \"Ne4=10, Kg1=1, Nd1=1, Rc8=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.044\";", "4r1k1/2pbqp1p/1r3p2/pP1p4/8/P1QBPN2/3P1PPP/4K2R w K - bm Nd4; c0 \"Nd4=10, Qxc7=6, a4=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.045\";", "4r1k1/3q1pp1/3p1n2/rp2nP1p/3B1R2/2N5/2PQ2PP/4R1K1 w - - bm Ne4; c0 \"Ne4=10, Kh1=8, Rb1=6, h3=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.046\";", "4r1k1/3r2p1/b1q2n1p/p7/Pp2P2Q/1N2BP2/1PP4P/2R1R2K w - - bm Nd4; c0 \"Nd4=10, Nc5=6, Nxa5=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.047\";", "4r3/1p3pk1/2p2n1p/2n1qP2/5bPQ/P3pB2/2R5/1R3N1K b - - bm Nfe4; c0 \"Nfe4=10, Nd3=9, Nh7=9, Qd4=2, Rd8=1\"; id \"STS: Knight Outposts/Repositioning/Centralization.048\";", "4rrk1/p4pp1/1b1p3p/2pP4/6q1/5N2/PP3PPP/2RQ1R1K w - - bm Nd2; c0 \"Nd2=10, Kg1=7, Qd3=2, h3=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.049\";", "5k2/6p1/Bnp1p2p/5p2/3P1n2/2q2P2/7P/5RQK b - - bm Nbd5; c0 \"Nbd5=10, Kf7=7, Kg8=4, g6=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.050\";", "5r1k/2p3q1/1p1npr2/pPn1N1pp/P1PN4/R4PPP/4Q1K1/3R4 w - - bm Ndc6; c0 \"Ndc6=10, Kh1=1, Rb1=8, Rc1=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.051\";", "5r2/2r2kp1/3n1p2/1p1Pp2p/p3P2P/PnP4R/1BB2KP1/4R3 b - - bm Nc4; c0 \"Nc4=10, Ke7=9, Rb8=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.052\";", "5rk1/3nbp1p/2p1p3/2PpP1pN/3P2B1/q3PQ1P/6P1/5RK1 w - - bm Nf6+; c0 \"Nf6+=10, Qf2=1, Qg3=4, h4=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.053\";", "5rk1/6pp/pn1qp1r1/1p2R3/2pP1P2/P1P2Q1P/5P2/2B1R2K b - - bm Nd5; c0 \"Nd5=10, Nd7=9, Qd7=9, Rgf6=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.054\";", "5rk1/pb1qbppp/1p6/n1rpP3/7P/2P2NP1/P3QPB1/R1BR2K1 w - - bm Nd4; c0 \"Nd4=10, Bb2=2, Bd2=1\"; id \"STS: Knight Outposts/Repositioning/Centralization.055\";", "6k1/3pbpp1/p3p2n/r3P2p/2rBNP2/2P3PP/P3R3/3R3K b - - bm Nf5; c0 \"Nf5=10, Rd5=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.056\";", "6k1/p2b3n/1p2pn1q/3r1p2/5P1B/P5NR/1Q2B1P1/4K3 b - - bm Ng4; c0 \"Ng4=10, Qf8=1\"; id \"STS: Knight Outposts/Repositioning/Centralization.057\";", "7k/Rb4r1/3pPp1q/1pp2P2/3n2BP/4N1K1/1P3Q2/8 b - - bm Nc6; c0 \"Nc6=10, Kg8=8, Kh7=6, Qxe3+=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.058\";", "8/1b5p/1p1rrkp1/p2p1p2/P2P3P/1R1B1N2/nP3PPK/3R4 w - - bm Ne5; c0 \"Ne5=10, Bb5=4, h5=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.059\";", "8/1p2kp2/p3pn2/4n1p1/1P2P3/P1r1NB1P/5PPK/R7 b - - bm Ne8; c0 \"Ne8=10, Nxf3+=1, b5=3, b6=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.060\";", "8/1q6/3pn1k1/2p1p1p1/2P1P1Pp/1rBP1p1P/2Q2P2/R5K1 b - - bm Nf4; c0 \"Nf4=10, Kf7=4, Kg7=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.061\";", "8/2k2p2/pr1pbpn1/2p5/2P1P1P1/2P1KP1p/7P/R2N1B2 b - - bm Ne5; c0 \"Ne5=10, Kd7=5, Rb3=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.062\";", "8/pB1b2k1/1p2pn2/5p2/5P1B/P7/3K1NPn/8 b - - bm Ne8; c0 \"Ne8=10, Bb5=8, Kg6=7, Nf1+=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.063\";", "b1r2r1k/p2qp1bp/1p1pn1p1/8/1PP2P2/R1NBB3/P2Q2PP/5RK1 w - - bm Nb5; c0 \"Nb5=10, Be2=7, Kh1=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.064\";", "b4q2/1r5k/3p4/1p1Pn2B/1PpQP3/2N4P/6P1/B5K1 w - - bm Nd1; c0 \"Nd1=10, Ne2=6, Qe3=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.065\";", "q3n3/2rp1ppk/2b4p/4p2P/p3P3/Pr2NBP1/1P1R1PK1/2R1Q3 w - - bm Nd5; c0 \"Nd5=10, Kg1=3, Qe2=1\"; id \"STS: Knight Outposts/Repositioning/Centralization.066\";", "r1b1k1nr/pp2p1bp/1q1p2p1/2pP4/2Pnp3/2NB1N1P/PP1B1PP1/R2QK2R w KQkq - bm Nxe4; c0 \"Nxe4=10, Bxe4=3, Na4=7, Nxd4=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.067\";", "r1b2r1k/pp3pbp/3n4/4p3/2N4R/2N5/PP3PPP/R1B3K1 b - - bm Nf5; c0 \"Nf5=10, Bf6=2, Nxc4=3, Rd8=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.068\";", "r1b2rk1/1pq1bppp/p2p4/P3p3/2N1n3/4B3/1PP1BPPP/R2QK2R w KQ - bm Nb6; c0 \"Nb6=10, O-O=9, f3=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.069\";", "r1b2rk1/p2q2b1/1nppp1pp/5pN1/P2P1B2/Q5P1/1P2PPBP/R1R3K1 b - - bm Nd5; c0 \"Nd5=10, Bb7=3, hxg5=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.070\";", "r1b2rk1/pp3pp1/2np2qp/b1p1p3/2P1P3/2NPB1P1/PP3PBP/R2Q1RK1 w - - bm Nd5; c0 \"Nd5=10, Qb3=1, Qc2=1, f4=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.071\";", "r1bq1rk1/ppp3bp/n2p1pp1/3P4/2P1Pp2/2N2N1P/PP2BPP1/R2QR1K1 w - - bm Nd4; c0 \"Nd4=10, Bf1=9, Qd2=4, Rc1=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.072\";", "r1r3k1/pb3p1p/1pqBp1p1/4P3/3b4/2P2P2/PR1N2PP/2RQ3K w - - bm Ne4; c0 \"Ne4=10\"; id \"STS: Knight Outposts/Repositioning/Centralization.073\";", "r2b2k1/2pr4/1pn1b1qp/3Np1p1/p1P1p3/1P2B1P1/PQ2PP1P/R2R2NK b - - bm Nd4; c0 \"Nd4=10, Bf5=4, a3=5, h5=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.074\";", "r2br3/p2b1q1k/n2P2pp/1p1N1p2/4pP2/BP2Q1PN/P1R4P/3R2K1 w - - bm Nc7; c0 \"Nc7=10, Nf2=3, Qd4=2, Qe2=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.075\";", "r2q1bk1/1p1brpp1/p1np1n1p/4p3/PN2P3/1QPP1N1P/B2B1PP1/R3R1K1 w - - bm Nd5; c0 \"Nd5=10, Be3=4, Qb2=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.076\";", "r2q1k2/2p2pb1/p2n2rp/1p1RB1p1/8/2PQRN1P/P4PP1/6K1 w - - bm Nd4; c0 \"Nd4=10, Bxg7+=2, Re2=3, h4=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.077\";", "r2q1rk1/3nbpp1/p2p3p/8/1p1BP3/3B2Q1/PPP4P/2KR3R b - - bm Ne5; c0 \"Ne5=10, Bf6=1, Bg5+=4, g6=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.078\";", "r2q1rk1/pp1bp1bp/5np1/2pP1p2/8/2N2NP1/PP2PPBP/2RQ1RK1 w - - bm Ne5; c0 \"Ne5=10, Ng5=5, Qb3=7, e3=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.079\";", "r2q2kr/p3n3/1p1Bp1bp/3pP1pN/5PPn/3B3Q/2P2K2/1R5R w - - bm Nf6+; c0 \"Nf6+=10, Bxg6=3, Rbg1=2\"; id \"STS: Knight Outposts/Repositioning/Centralization.080\";", "r2qk2r/1bpnnpbp/p2pp1p1/4P3/Pp1P1P2/2NBBN2/1PP3PP/R2Q1RK1 w kq - bm Ne4; c0 \"Ne4=10, Na2=2, Ne2=2, exd6=8\"; id \"STS: Knight Outposts/Repositioning/Centralization.081\";", "r2qr1k1/pp3ppp/2n2nb1/1P4B1/3p4/P2B1P2/2P1N1PP/R2Q1RK1 b - - bm Ne5; c0 \"Ne5=10, Na5=9, Ne7=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.082\";", "r2r2k1/1bqn1pp1/1p1p1b1p/1B2n3/2P1P3/P1N1B3/1P1NQ1PP/4RR1K w - - bm Nd5; c0 \"Nd5=10, Bd4=9, Nb3=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.083\";", "r2r2k1/1p1n2q1/2ppbp2/6p1/2PBP2p/p1N2P2/Pb4PP/1R1RQBK1 b - - bm Ne5; c0 \"Ne5=10, Qf7=2, Qh7=5, h3=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.084\";", "r2rq3/pp1b3k/n2P1bpp/4pp2/8/BPN1Q1PN/P4P1P/2RR2K1 w - - bm Nd5; c0 \"Nd5=10, Bb2=5, Qd3=5, Qf3=5, f3=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.085\";", "r3r1k1/1b1nq2p/p2pNppQ/1ppP3n/P3P3/7P/1PB2PP1/R3RNK1 b - - bm Nf8; c0 \"Nf8=10, Ne5=4, Rec8=6\"; id \"STS: Knight Outposts/Repositioning/Centralization.086\";", "r3r1k1/1p1q2bp/1n1p2p1/1PpPpp1n/p3P3/R1NQBN1P/1PP2PP1/4R1K1 w - - bm Ng5; c0 \"Ng5=10, Qf1=7, Rd1=8, exf5=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.087\";", "r3r1k1/3nbppp/p1q5/1pp1P2b/5B2/1P2QN2/1P1N1PPP/3RR1K1 w - - bm Ne4; c0 \"Ne4=10, Bg3=7, Rc1=7\"; id \"STS: Knight Outposts/Repositioning/Centralization.088\";", "r3r1k1/4bppp/pnq5/1pp1P2b/4NB2/1P2QN2/1P3PPP/3RR1K1 w - - bm Nd6; c0 \"Nd6=10, Bg3=4, Qc1=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.089\";", "r3r2k/pp3pp1/1np4p/3p2q1/1P1P2b1/P1NBP3/2Q2PPP/R4RK1 w - - bm Ne2; c0 \"Ne2=10, Kh1=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.090\";", "r3r3/2P4k/3Bbbqp/ppQ2pp1/4pPP1/1P6/P1R2N1P/3R2K1 w - - bm Nxe4; c0 \"Nxe4=10, Qe3=4, Rcd2=5, Re2=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.091\";", "r3rnk1/1bpq1pp1/p2p3p/1p1Pp1b1/P3P1P1/1BP1N1P1/1P3P2/R1BQR1K1 w - - bm Nf5; c0 \"Nf5=10, Bc2=3, Kg2=4, Kg2=9, Qe2=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.092\";", "r4rk1/1b1q1ppp/pb1p1nn1/1pp1p3/1PP1P3/P2PNN1P/B2B1PP1/2RQR1K1 w - - bm Nf5; c0 \"Nf5=10, Bb1=7, Qb3=4\"; id \"STS: Knight Outposts/Repositioning/Centralization.093\";", "r4rk1/1pq1bppp/1n2p3/p1n1P3/2PR4/2N1BN2/P3QPPP/1R4K1 w - - bm Nb5; c0 \"Nb5=10, Qd2=5, h4=9\"; id \"STS: Knight Outposts/Repositioning/Centralization.094\";", "r4rk1/5p1p/p2qpnp1/1p2b3/3p4/3B1R2/PPQ3PP/R1BN3K b - - bm Nd7; c0 \"Nd7=10, Nd5=7, Nh5=5, Rac8=1, Rfc8=1\"; id \"STS: Knight Outposts/Repositioning/Centralization.095\";", "r4rk1/ppp3b1/3p1q1p/3Ppn2/P1P3n1/2NQ1N2/1P1B1PP1/R3R1K1 w - - bm Ne4; c0 \"Ne4=10, Nb5=4, Nh2=1, Ra3=1\"; id \"STS: Knight Outposts/Repositioning/Centralization.096\";", "r5r1/1pp2k1p/2bn4/2p3B1/p3pPP1/1P2N2P/P1P1R3/R5K1 b - - bm Nb5; c0 \"Nb5=10\"; id \"STS: Knight Outposts/Repositioning/Centralization.097\";", "r6k/pp3pp1/1n6/1pQp1q2/3PrN1p/P3P2P/5PP1/2R2RK1 w - - bm Nd3; c0 \"Nd3=10, Ne2=2, Qxb5=2, Rce1=3\"; id \"STS: Knight Outposts/Repositioning/Centralization.098\";", "r6r/1q1bbkp1/p1p1pn2/5p1p/N2Bp3/2Q3P1/PPP2PBP/R2R2K1 b - - bm Nd5; c0 \"Nd5=10, Rad8=5, h4=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.099\";", "rqr3k1/1p2bppp/3pn3/p3p1Pn/P3P3/1PNBBP2/1P1Q3P/2KR3R b - - bm Nd4; c0 \"Nd4=10, Nef4=6, Nhf4=5\"; id \"STS: Knight Outposts/Repositioning/Centralization.100\";", "6k1/p2pp2p/bp4n1/q1r4R/1RP1P3/2P2B2/P2Q2P1/4K3 w - - bm Rd5; c0 \"Rd5=10, Rf5=6, g4=7\"; id \"STS(v4.0) Square Vacancy.001\";", "r2r2k1/pp3ppp/2p1qn2/5N1b/1n2PP2/4Q2P/PPP3B1/R1B2RK1 w - - bm Qc5; c0 \"Qc5=10, Qg3=3\"; id \"STS(v4.0) Square Vacancy.002\";", "3r4/p4pk1/P1pr3p/3nb3/1p6/5B1P/1P3PP1/R1BR2K1 w - - bm Ra5; c0 \"Ra5=10, Kf1=2, g3=5\"; id \"STS(v4.0) Square Vacancy.003\";", "1b1r3r/3pkpp1/3np1q1/2p5/2P1PPP1/5Q2/PP4B1/R1BR2K1 b - - bm Rh4; c0 \"Rh4=10, Nxc4=6, Rc8=7\"; id \"STS(v4.0) Square Vacancy.004\";", "7k/1p6/1n1rrq1p/1R1p1p1p/3P1P2/QR2P2P/6PK/5B2 w - - bm Qa7; c0 \"Qa7=10, Kg1=7, R5b4=7\"; id \"STS(v4.0) Square Vacancy.005\";", "5r1k/5rp1/p1n1p1qp/2P1p3/P7/4QN1P/5PP1/2R1R2K w - - bm Rc4; c0 \"Rc4=10, Qe2=5, Rc3=7\"; id \"STS(v4.0) Square Vacancy.006\";", "6r1/1p2Q1pk/2p2p1p/3p1P1P/p1nP4/PqP1P3/1P2RN2/2K5 b - - bm Qa2; c0 \"Qa2=10, Qb5=5, b6=3\"; id \"STS(v4.0) Square Vacancy.007\";", "6r1/1p2Q1pk/2p2p1p/n2p1P1P/p2P4/P1P1P3/1P1KR3/q2N4 b - - bm Qb1; c0 \"Qb1=10, Kh8=3, Nb3+=4\"; id \"STS(v4.0) Square Vacancy.008\";", "5r1k/1b3pp1/p3pb2/4N2q/3R1B2/4P3/1PB2PPP/1K4R1 b - - bm Qe2; c0 \"Qe2=10, Bxe5=7, Kg8=4\"; id \"STS(v4.0) Square Vacancy.009\";", "8/1b2r2p/1p1r1kp1/p2p1p2/Pn1P3P/1R1B1N2/1P3PPK/2R5 w - - bm Bb5; c0 \"Bb5=10, Bf1=2, Ne5=6\"; id \"STS(v4.0) Square Vacancy.010\";", "1q1k2r1/p2bn3/1r3n2/2QPp1Rp/2P4P/2PB1P2/2K1N3/R7 w - - bm Qa5; c0 \"Qa5=10, Qa3=4, Rxg8+=5\"; id \"STS(v4.0) Square Vacancy.011\";", "8/p3q1kp/1p1p1rp1/3Bn3/P1PQ1p2/1P6/6PP/4R2K b - - bm Rf5; c0 \"Rf5=10, Kh6=6, Rf8=3\"; id \"STS(v4.0) Square Vacancy.012\";", "4r1rk/pp6/5q2/3pNp1P/2pPnQ2/2P1P2P/P6K/R5R1 w - - bm Rg6; c0 \"Rg6=10, Rab1=4, Rac1=4\"; id \"STS(v4.0) Square Vacancy.013\";", "5r2/p1qn3k/bp1p1pp1/3P4/P2BPP2/2Pp4/3N2P1/R2Q2K1 w - - bm Qg4; c0 \"Qg4=10, Qe1=4, a5=5\"; id \"STS(v4.0) Square Vacancy.014\";", "1r3q2/1n4pk/R4p1p/4p2P/2B1P1P1/2P1QPK1/8/8 w - - bm Be6; c0 \"Be6=10, Bd5=7, Rb6=8\"; id \"STS(v4.0) Square Vacancy.015\";", "4r1k1/1pb3p1/p1p3q1/3n4/1P1P4/P3pRP1/4Q1K1/2B2R2 b - - bm Qe4; c0 \"Qe4=10, Bb6=5, Bd8=5\"; id \"STS(v4.0) Square Vacancy.016\";", "3R4/pkn5/1p2qp2/1p5p/1P2P1pR/P5P1/1N3PP1/5K2 b - - bm Qb3; c0 \"Qb3=10, Qa2=5\"; id \"STS(v4.0) Square Vacancy.017\";", "4r1k1/p5pp/4q3/P2R4/2p2P2/2N3P1/2nB1K1P/1R6 b - - bm Qh3; c0 \"Qh3=10, a6=5, h6=6\"; id \"STS(v4.0) Square Vacancy.018\";", "1Q6/1p2p2k/1r4pp/p1p2P2/q2nr1P1/7R/1P1R4/5NK1 w - - bm Qf8; c0 \"Qf8=10, Kh2=7, Rg2=7\"; id \"STS(v4.0) Square Vacancy.019\";", "4R3/p2q2k1/2p2r1p/6p1/8/P5P1/4QP1P/3rB1K1 b - - bm Qd4; c0 \"Qd4=10, Kf7=6, Kg6=6\"; id \"STS(v4.0) Square Vacancy.020\";", "3q1r1k/5ppp/1pR1pn2/p7/B1PP4/P3QP1P/5PK1/8 w - - bm Qe5; id \"STS(v4.0) Square Vacancy.021\"; c0 \"Qe5=10, f4=1, Kf1=1, Kh2=1\";", "8/Qpnbk2q/4pp2/1P1p4/P1r5/2P3P1/1K2N3/1R3B2 b - - bm Qd3; c0 \"Qd3=10, Qh2=2, e5=2\"; id \"STS(v4.0) Square Vacancy.022\";", "2r2rk1/pb2qp1p/n3p1p1/2pp4/N1P1n3/1P2P1P1/PN3PBP/2R1QRK1 w - - bm Qa5; c0 \"Qa5=10, Qe2=6, Rd1=4\"; id \"STS(v4.0) Square Vacancy.023\";", "r5k1/1p5p/p1p1qrnP/2B1pb2/R1P5/2P2B2/P2Q2P1/5RK1 w - - bm Qg5; c0 \"Qg5=10, Qb2=1, Rb4=6\"; id \"STS(4.0) Square Vacancy.024\";", "Q7/2pq3k/1rp2b1p/2R5/8/1P1NP3/P2K1Pr1/5R2 w - - bm Qf8; c0 \"Qf8=10, Qa4=5, Rc2=4\"; id \"STS(v4.0) Square Vacancy.025\";", "q5k1/p2p2bp/1p1p2r1/2p1np2/6p1/1PP2PP1/P2PQ1KP/4R1NR b - - bm Qd5; c0 \"Qd5=10, Re6=4, a5=1, c4=2\"; id \"STS(v4.0) Square Vacancy.026\";", "4r1k1/1p5p/1nq1p1p1/4B3/6R1/P6P/3Q1PPK/8 w - - bm Qh6; c0 \"Qh6=10, Ba1=4, Qd3=4\"; id \"STS(v4.0) Square Vacancy.027\";", "r5nk/p4p1r/qp1Rb2p/2p1Pp2/5P1Q/P4N2/2B3PP/5RK1 w - - bm Qh5; c0 \"Qh5=10, a4=2\"; id \"STS(v4.0) Square Vacancy.028\";", "r2r2k1/1q2bpp1/4p2p/p6Q/N4P2/1P2R1P1/2P4P/2KR4 b - - bm Qb4; c0 \"Qb4=10, Qg2=5, Rdc8=5\"; id \"STS(v4.0) Square Vacancy.029\";", "r4rk1/1b2bpp1/1P1p4/p1q1p2p/R3PPn1/3B3Q/2P1N1PP/1R1N3K b - - bm Qf2; c0 \"Qf2=10, d5=1\"; id \"STS(v4.0) Square Vacancy.030\";", "1r5r/1p6/p2p2p1/P2P1pkq/1R1Qp3/2P1P1bP/1P2R3/5BK1 b - - bm Qf3; c0 \"Qf3=10, Be5=8, Rh6=5\"; id \"STS(v4.0) Square Vacancy.031\";", "2r1r2k/q6p/6p1/3R1p2/1p1P1B2/2bQPBP1/5P1P/6K1 w - - bm Qb5; c0 \"Qb5=10, Kg2=5, Rb5=5\"; id \"STS(v4.0) Square Vacancy.032\";", "1r3q1k/6p1/r6p/3P3b/2PQ1R2/pp4P1/5P2/R1B3K1 b - - bm Qb4; c0 \"Qb4=10, Qd6=1, Qe7=1\"; id \"STS(v4.0) Square Vacancy.033\";", "5k2/pb3pp1/qp3n1p/2p5/2P2B2/8/P1PN1PPP/R3R1K1 b - - bm Qa4; c0 \"Qa4=10, Bc6=1\"; id \"STS(v4.0) Square Vacancy.034\";", "2r1qr1k/1p4bp/p1n1bpp1/4p3/B3P3/4QN1P/PP1B1PP1/R1R3K1 w - - bm Qb6; c0 \"Qb6=10, Rc2=5, Rc3=5, a3=4\"; id \"STS(v4.0) Square Vacancy.035\";", "6rk/5q1p/p2p4/P1nP1p2/2B2N1Q/1Pb1pPR1/7P/7K w - - bm Qh6; c0 \"Qh6=10, Rg5=3, Rxg8+=5\"; id \"STS(v4.0) Square Vacancy.036\";", "3r2k1/p4rp1/1pRp3q/1P1Ppb2/7P/Q4P2/P5BP/2R4K b - - bm Qd2; c0 \"Qd2=10, Kh7=5, Qf4=4\"; id \"STS(v4.0) Square Vacancy.037\";", "rq4k1/3bn1bp/3p2p1/3Pp1N1/4P1p1/2N1B1P1/1P2QP1P/4R1K1 b - - bm Qb3; c0 \"Qb3=10, Kh8=4, h5=4\"; id \"STS(v4.0) Square Vacancy.038\";", "3rk3/2p1r1p1/7q/p1p1P1R1/2B4P/4P3/PPQ5/6K1 w - - bm Qe4; c0 \"Qe4=10, Kg2=4, b3=3\"; id \"STS(v4.0) Square Vacancy.039\";", "2r2r1k/3q2np/p2P1pp1/1pP1p3/7N/5QP1/P4P1P/2R1R1K1 w - - bm Qd5; c0 \"Qd5=10, Qd1=7, Qd3=7\"; id \"STS(v4.0) Square Vacancy.040\";", "r2r2k1/5p1p/6nQ/ppq5/2p1P3/P4P2/1P4PP/R1N2R1K b - - bm Qd4; c0 \"Qd4=10, Qd6=5, Qf2=1\"; id \"STS(v4.0) Square Vacancy.041\";", "r3r1k1/ppq3p1/2p1n3/3pN1p1/Pb1P2P1/3QB2P/1P3P2/R1R3K1 w - - bm Qf5; c0 \"Qf5=10, Kg2=4, Ng6=3, Qg6=4, Rc2=4\"; id \"STS(v4.0) Square Vacancy.042\";", "2bq1rk1/1r3p2/3p2pp/p1p1p3/PnP1P3/2QPP1N1/2B3PP/1R3RK1 b - - bm Qg5; c0 \"Qg5=10, Bd7=3, Qe8=3, h5=4\"; id \"STS(v4.0) Square Vacancy.043\";", "2q5/5kp1/pP2p1r1/3b1p1Q/3P1P2/6P1/5K2/4RB2 b - - bm Qc3; c0 \"Qc3=10, Bb7=2, Qc2+=3, Qc6=1\"; id \"STS(v4.0) Square Vacancy.044\";", "2q2r1k/7p/p2p1p2/1p1Np3/nP6/4Q2P/P4PP1/4R1K1 w - - bm Qh6; c0 \"Qh6=10, Qd2=2, Rc1=6, Re2=1\"; id \"STS(v4.0) Square Vacancy.045\";", "8/3k4/2p5/3r4/1PQBp1pq/4P3/P4PpP/6K1 w - - bm Qa6; c0 \"Qa6=10, Kxg2=4, a4=6, b5=5\"; id \"STS(v4.0) Square Vacancy.046\";", "8/7p/p2p1kqP/2r1b3/P1B1p1r1/1P6/4QP2/3R1K1R b - - bm Qf5; c0 \"Qf5=10, Qg5=1, Rf4=3, a5=3\"; id \"STS(v4.0) Square Vacancy.047\";", "2b1rnk1/1p3pp1/r3p2p/1q2P3/p2PQ3/P1P2PB1/6PP/1BKR3R b - - bm Qb3; c0 \"Qb3=10, Bd7=5, Qa5=4, Rc6=4\"; id \"STS(v4.0) Square Vacancy.048\";", "2r5/p4kp1/1pn2n2/3q1b2/3p4/P2P2Q1/2RB1PPP/4R1K1 b - - bm Qb3; c0 \"Qb3=10, Nd7=5, Nh5=3, Qb5=3\"; id \"STS(v4.0) Square Vacancy.049\";", "r6k/1p2rR1P/2p3p1/4p1q1/8/pP6/P1P5/1K2Q2R w - - bm Qa5; c0 \"Qa5=10, Rf2=6, Rf3=6, Rff1=6\"; id \"STS(v4.0) Square Vacancy.050\";", "r3r1k1/2q3p1/p2p1p2/3P2p1/n2B2P1/8/P1PQ3P/K2R1R2 b - - bm Qc4; c0 \"Qc4=10, Qc8=2, Rac8=6, Re4=6\"; id \"STS(v4.0) Square Vacancy.051\";", "3r2k1/2p2pp1/p6p/1p5q/1PbB4/P1Q3P1/5P1P/4R1K1 b - - bm Qg4; c0 \"Qg4=10, Rd6=2, a5=2, f6=2\"; id \"STS(v4.0) Square Vacancy.052\";", "r5k1/1q4b1/6n1/3pp1Nn/1N3p2/3P2Pp/2QBP2P/1R4K1 w - - bm Qc5; c0 \"Qc5=10, Nxh3=4\"; id \"STS(v4.0) Square Vacancy.053\";", "6r1/4pp1k/3p3p/2qP1P2/r3P1PK/1R6/4Q3/1R6 b - - bm Qd4; c0 \"Qd4=10, Ra3=1, Rg5=1, Rga8=2, d5d4=1\"; id \"STS(v4.0) Square Vacancy.054\";", "8/p3b1k1/2p5/3qp2p/P2p3P/1P1Q1PP1/3NP1K1/8 w - - bm Qf5; c0 \"Qf5=10, Nc4=7, Qa6=6, Qb1=5, Qc2=5\"; id \"STS(v4.0) Square Vacancy.055\";", "1rb2rk1/2p3pp/p1p1p3/2N5/8/1PQ2PPq/P3P3/R2R2K1 w - - bm Qe5; c0 \"Qe5=10, Kf2=4, Ne4=6\"; id \"STS(v4.0) Square Vacancy.056\";", "2rqrbk1/1b1n1p2/p2p1npp/1p6/4P2B/1B3NNP/PP1Q1PP1/3RR1K1 w - - bm Qf4; c0 \"Qf4=10, Re2=3, a3=1, a4=2\"; id \"STS(v4.0) Square Vacancy.057\";", "r1k5/4qp2/P1p1b1p1/6Pp/n3P2P/6Q1/2N5/1K1R2R1 b - - bm Qc5; c0 \"Qc5=10, Rxa6=2\"; id \"STS(v4.0) Square Vacancy.058\";", "6k1/3qbp1p/6p1/3Pp1P1/3n3P/pP1Q4/P7/1K2B2B b - - bm Qg4; c0 \"Qg4=10, Bd6=5, Kf8=3, h6=3\"; id \"STS(v4.0) Square Vacancy.059\";", "3n4/p2rk3/3pq1p1/pR3p1p/2PQ1P2/1PB4P/6PK/8 w - - bm Qh8; c0 \"Qh8=10, Bb2=5, Kh1=5, Rb8=6, Rd5=5\"; id \"STS(v4.0) Square Vacancy.060\";", "5b1k/r7/Pq5p/2p5/3p3N/R2Q2P1/5PK1/8 w - - bm Qf5; c0 \"Qf5=10, Ng6+=2, Qf3=8, Qg6=2\"; id \"STS(v4.0) Square Vacancy.061\";", "5rk1/3n4/3Rp1p1/2P2q1p/1p1P2n1/6P1/1B1NQ2P/6K1 b - - bm Qc2; id \"STS(v4.0) Square Vacancy.062\"; c0 \"Qc2=10, Ndf6=4, Nxc5=4\";", "2r3k1/5pbp/2pB2p1/p3P3/2R2P2/2Q3P1/5K1P/1q6 b - - bm Qh1; c0 \"Qh1=10, Qa2+=2, Qb6+=3, c5=2\"; id \"STS(v4.0) Square Vacancy.063\";", "5r2/3q2pk/5n1p/3p1p1P/1p1P4/4PP2/1P2R1PQ/2rNR1K1 b - - bm Qb5; c0 \"Qb5=10, Re8=4\"; id \"STS(v4.0) Square Vacancy.064\";", "5r1k/2pb1q2/1p1p4/pP1Pp1Rp/2P1P3/1KN4r/P7/4Q2R b - - bm Qf3; c0 \"Qf3=10, Qh7=4, Rg8=2, Rxh1=3\"; id \"STS(v4.0) Square Vacancy.065\";", "7k/p4r2/b3p2q/Pp1p2pp/3P2p1/1P2P1P1/2Q2PBP/2R3K1 w - - bm Qc6; c0 \"Qc6=10, Bf1=5, Qe2=4, e4=6\"; id \"STS(v4.0) Square Vacancy.066\";", "3r1k2/2q5/1p6/5P1p/pP2Q3/P2p4/3R4/1K6 b - - bm Qg3; c0 \"Qg3=10, Qc3=5, Qe7=7, Re8=4\"; id \"STS(v4.0) Square Vacancy.067\";", "6k1/4bp2/4q3/3pP3/p1pr3p/P1NbQR2/1P4PR/3K4 b - - bm Qg4; c0 \"Qg4=10, Bc2+=4, Rg4=6\"; id \"STS(v4.0) Square Vacancy.068\";", "5bk1/3r1p1p/3P1Pp1/1q4Pn/2pN3P/1P2B3/1K3Q2/R7 b - - bm Qe5; c0 \"Qe5=10, Qb8=7, Qc5=4, Qd5=8\"; id \"STS(v4.0) Square Vacancy.069\";", "1r1n3k/1pq3pp/p2Nrn2/2P1p3/3p4/Q2P2P1/4PPB1/1RR3K1 w - - bm Rb6; c0 \"Rb6=10, Qa2=4, Qa4=4, Qb3=4, Rb3=5\"; id \"STS(v4.0) Square Vacancy.070\";", "3r1q1k/6pp/4R3/8/n2p1PB1/3PpQP1/4P1K1/8 w - - bm Qc6; c0 \"Qc6=10, Bh3=3, Kh2=3, Re5=3, f5=3\"; id \"STS(v4.0) Square Vacancy.071\";", "8/1p3q1k/p1p2b1P/2B1nP2/8/1Pn2PN1/2Q3P1/6K1 b - - bm Qd5; c0 \"Qd5=10, Bh4=3, Nd5=3, Nd7=5\"; id \"STS(v4.0) Square Vacancy.072\";", "2r4k/7p/2q2nr1/p3R3/Ppp1P3/7P/P1B3P1/3R1Q1K w - - bm Qf5; c0 \"Qf5=10, Qf3=4, Rd2=4, Re7=2\"; id \"STS(v4.0) Square Vacancy.073\";", "bq6/4bk1p/1B1p2p1/3Ppp2/2P5/7P/1Q1N1PP1/6K1 w - - bm Qb5; c0 \"Qb5=10, Qb1=2, Qb3=4, Qb4=2\"; id \"STS(v4.0) Square Vacancy.074\";", "b3qbk1/B6p/1QNp2p1/3Pp3/2P2p2/5P1P/6P1/6K1 w - - bm Qc7; c0 \"Qc7=10, Kh2=2, Nd8=4, Qb5=2\"; id \"STS(v4.0) Square Vacancy.075\";", "r3r1k1/1b3p1p/3b2p1/p2Pp1P1/1pq1B3/4B3/PPP3QP/1K1R1R2 w - - bm Rf6; c0 \"Rf6=10, Bd3=2, b3=1, h4=3\"; id \"STS(v4.0) Square Vacancy.076\";", "r4q1k/1p2b2r/7P/p1pPp3/8/P2PP1R1/1P4Q1/1K5R w - - bm Qe4; c0 \"Qe4=10, Rf1=5, Rg4=5, Rg7=5\"; id \"STS(v4.0) Square Vacancy.077\";", "2b1q3/p4rbk/1p1R2pp/1P1N4/P2pPp2/B4P1P/4Q1P1/6K1 w - - bm Qc4; c0 \"Qc4=10, Nb4=5, Qd2=2, Qd3=2\"; id \"STS(v4.0) Square Vacancy.078\";", "r1b2rk1/p6p/1p1P1pp1/q1p5/2P1PQ2/P7/1R2B1PP/5R1K b - - bm Qc3; c0 \"Qc3=10, Bb7=3, Bd7=1, Be6=2\"; id \"STS(v4.0) Square Vacancy.079\";", "2b2kn1/5pp1/r2q3p/p2pN3/2pP1PP1/5P2/P1Q4P/1B2R2K w - - bm Qh7; c0 \"Qh7=10, Kg1=6, Qc3=6, g5=6\"; id \"STS(v4.0) Square Vacancy.080\";", "2r1r3/1Rpp2pk/2n4p/p1PNqp2/P3p3/2P1P1P1/4QP1P/3R2K1 w - - bm Qh5; c0 \"Qh5=10, Nf4=5, Qa6=2, Rb5=2\"; id \"STS(v4.0) Square Vacancy.081\";", "r1b1k2r/2q1pp2/1p5p/p1pPp1p1/2P5/3B3P/PP2QPP1/4RRK1 w kq - bm Qh5; c0 \"Qh5=10, Bc2=4, Qxe5=4, a3=4\"; id \"STS(v4.0) Square Vacancy.082\";", "1rr3k1/pp3p1p/6p1/1PPB4/4P2q/2Q2P2/P4P1P/2R2K2 w - - bm Qe5; c0 \"Qe5=10, Kg1=3, Kg2=3, Rd1=3\"; id \"STS(v4.0) Square Vacancy.083\";", "r2bn1k1/1p3pp1/pqb1p2p/4B3/2B2Q1P/2N2P2/PPP3P1/1K1R4 b - - bm Qf2; c0 \"Qf2=10, Bf6=1, Qc5=2, Rc8=1\"; id \"STS(v4.0) Square Vacancy.084\";", "7r/q3kp2/2rp1p2/3RpPb1/1p2P1P1/1P1N4/P4R1P/1K2Q3 b - - bm Qa3; c0 \"Qa3=10, Kd7=2\"; id \"STS(v4.0) Square Vacancy.085\";", "1n2r1k1/1q4pp/4pp2/p1R5/Pp1Q4/4B2P/1P3PP1/6K1 w - - bm Qd6; c0 \"Qd6=10, Qc4=5, Qd3=5, Qg4=4\"; id \"STS(v4.0) Square Vacancy.086\";", "2r5/p4p1k/1p5p/2qPnN2/P2R4/1P4Pp/7P/3Q2K1 b - - bm Qc3; c0 \"Qc3=10, Qc1=2\"; id \"STS(v4.0) Square Vacancy.087\";", "4r1k1/1rp2ppp/p3b3/1n1p4/1q1P1B2/1P3P1P/P1Q3P1/3RRNK1 w - - bm Qc6; c0 \"Qc6=10, Ne3=4, Qd2=5, Qd3=5, Qf2=3\"; id \"STS(v4.0) Square Vacancy.088\";", "r1b1n2r/1p1pqpkp/p1n1p3/4P3/4NP2/3B3P/PPP3P1/R2Q1R1K w - - bm Qh5; c0 \"Qh5=10, Qg4+=7, c4=7, f5=7\"; id \"STS(v4.0) Square Vacancy.089\";", "6rk/5Qp1/7p/4p2P/1p1rq3/6R1/PP6/K5R1 b - - bm Qc2; c0 \"Qc2=10, Qd5=3, Qe2=5, Qf4=5\"; id \"STS(v4.0) Square Vacancy.090\";", "3r2k1/5pb1/5qpp/1Np5/8/1P3P1P/1PQ3P1/1K5R b - - bm Qg5; c0 \"Qg5=10, Qa6=3, Qh4=3, Rb8=4\"; id \"STS(v4.0) Square Vacancy.091\";", "5k2/q7/2p5/4pppn/1pP2nN1/1P2RPPP/3r1B1K/4Q3 b - - bm Qd4; c0 \"Qd4=10, Nxg3=2, Rxf2+=4\"; id \"STS(v4.0) Square Vacancy.092\";", "2q2rk1/p1P1bppp/Pn3n2/3p1b2/3P1B2/1P3N1P/4BPP1/2Q2RK1 w - - bm Qc6; c0 \"Qc6=10, Nh4=7, Qe3=7, g4=6\"; id \"STS(v4.0) Square Vacancy.093\";", "5rk1/1Q3pp1/p2ppq1p/6b1/N2NP1P1/8/PP2K1P1/3R4 b - - bm Qf4; c0 \"Qf4=10, Qe5=5, a5=6, d5=6\"; id \"STS(v4.0) Square Vacancy.094\";", "2k3r1/1b1n1p2/5n2/1Rp1q2p/1pPpP1p1/1N3P2/4B1PP/Q4RK1 w - - bm Qa7; c0 \"Qa7=10, Qa5=1, Rf2=2, fxg4=3\"; id \"STS(v4.0) Square Vacancy.095\";", "r3r1k1/5pp1/p2p3p/2nPP3/p5q1/2P1RNP1/2Q2P1P/2R3K1 b - - bm Qc4; c0 \"Qc4=10, Rac8=3, Rad8=3\"; id \"STS(v4.0) Square Vacancy.096\";", "7k/ppr1qpb1/1n2pN1p/4P1p1/8/1B3QP1/PP3PKP/4R3 w - - bm Qh5; c0 \"Qh5=10, Re2=3, Re3=1, h3=2\"; id \"STS(v4.0) Square Vacancy.097\";", "3r2k1/R5p1/2b2npp/1pP5/4pP1P/6Pq/1Q2BP2/4B1K1 w - - bm Qe5; c0 \"Qe5=10, Bf1=2, Ra6=3, Rc7=6\"; id \"STS(v4.0) Square Vacancy.098\";", "3r4/k1pr4/npR1p3/p3Pp1p/P1QP2pN/q5P1/6PP/1R5K b - - bm Qe3; c0 \"Qe3=10, Kb7=4, Qe7=5, f4=4\"; id \"STS(v4.0) Square Vacancy.099\";", "R7/2q3k1/p1r2p1n/2p1pPp1/P3P3/2PP4/7Q/5BK1 w - - bm Qh5; c0 \"Qh5=10, Be2=1, Qb2=1, Qe2=1\"; id \"STS(v4.0) Square Vacancy.100\";", "1b3rk1/5ppp/2p2rq1/1p1n4/3P2P1/1BPbBP2/1P1N2QP/R3R1K1 w - - bm Bxd5; id \"STS(v5.0) Bishop vs Knight.001\";", "1k1r2r1/1p2bp2/4q2p/p1ppP3/6b1/2PQ2B1/PP2NPP1/R1R3K1 b - - bm Bxe2; id \"STS(v5.0) Bishop vs Knight.002\";", "1q2n1k1/r4pb1/6p1/1bpPN1Pp/p1N1PP2/3B2KP/R3Q3/8 b - - bm Bxe5; id \"STS(v5.0) Bishop vs Knight.003\";", "1r1qr1k1/1b1nbpp1/ppnp3p/8/2P1PBB1/2N5/PPNQ2PP/2R2RK1 w - - bm Bxd7; id \"STS(v5.0) Bishop vs Knight.004\";", "1r1r2k1/2qp1ppp/2pbpn2/8/3BP3/3B2P1/P1P2P1P/R2Q1RK1 w - - bm Bxf6; id \"STS(v5.0) Bishop vs Knight.005\";", "1r1r2n1/1pb3pk/p1p3bp/4Np2/3P2P1/2N1RB1P/PP3PK1/4R3 w - - bm Nxg6; id \"STS(v5.0) Bishop vs Knight.006\";", "1r2r1k1/2q3p1/3bp2p/p2nNp2/1ppP1P2/2P3Q1/PP1RN1PP/R5K1 b - - bm Bxe5; id \"STS(v5.0) Bishop vs Knight.007\";", "1r2rbk1/1bqn1pp1/pp1p2np/3N1p2/2P1P3/PP2B1PB/4NQKP/2RR4 b - - bm Bxd5; id \"STS(v5.0) Bishop vs Knight.008\";", "1r3bk1/1q2r1p1/pp1p3p/2nP2p1/3BP3/PP3QP1/4N1KP/2RR4 w - - bm Bxc5; id \"STS(v5.0) Bishop vs Knight.009\";", "1r4k1/2qnbpp1/r3p2p/3pP2b/1p1N4/3P1NP1/nBPQ1PBP/R3R1K1 b - - bm Bxf3; id \"STS(v5.0) Bishop vs Knight.010\";", "1r4k1/6pp/2b3n1/Nnq1p3/4Pp2/3B2PP/4QP1K/2B1R3 w - - bm Nxc6; id \"STS(v5.0) Bishop vs Knight.011\";", "1rr4k/5p1p/4b1p1/pp1Nb3/4P3/PP1N1P2/K5RP/3R4 b - - bm Bxd5; id \"STS(v5.0) Bishop vs Knight.012\";", "2b1rr2/4q1pk/p2ppb1p/1p2n3/4PNB1/P1N4Q/1PP3PP/R4R1K b - - bm Nxg4; id \"STS(v5.0) Bishop vs Knight.013\";", "2b1rr2/4q1pk/p2ppb1p/1p5P/4PNQ1/P1N5/1PP3P1/R4R1K b - - bm Bxc3; id \"STS(v5.0) Bishop vs Knight.014\";", "2b3k1/p3qpbp/2p3p1/1pn1p3/4P3/PBP1NN1P/1PQ2PP1/6K1 b - - bm Nxb3; id \"STS(v5.0) Bishop vs Knight.015\";", "2k5/1p1nbqpp/pPprp1b1/P1p1p3/2P1P2N/4BP1P/1Q1N2P1/3R2K1 w - - bm Nxg6; id \"STS(v5.0) Bishop vs Knight.016\";", "2k5/p7/1pp3r1/6b1/3P1p1p/P4NrP/1PP2R2/1K1R4 w - - bm Nxg5; id \"STS(v5.0) Bishop vs Knight.017\";", "2kr1b1r/p1qn3p/Ppp3p1/4np2/8/2NBBP2/1PP3PP/RQ2R1K1 b - - bm Nxd3; id \"STS(v5.0) Bishop vs Knight.018\";", "2kr3b/1pr2p1p/p1n1p1p1/2NpPn2/1P1P4/3RBP1B/1P2KP1P/6R1 w - - bm Bxf5; id \"STS(v5.0) Bishop vs Knight.019\";", "2krr3/pp1qbp2/4b3/1P2P2p/P1pPB1pN/4B1Q1/5PPP/3R2K1 b - - bm Bxh4; id \"STS(v5.0) Bishop vs Knight.020\";", "2n2rk1/p2b2bp/3p2p1/q1pPp2n/P1P1P3/1QN5/3BBNPP/1R4K1 w - - bm Bxh5; id \"STS(v5.0) Bishop vs Knight.021\";", "2q3k1/1b4r1/p2np2p/QnBpN3/3P1pPp/1P1BP3/8/R5K1 w - - bm Bxb5; id \"STS(v5.0) Bishop vs Knight.022\";", "2r1r1k1/1q1bp1bp/3p2p1/1pnP4/3NB3/1P2BP2/3Q2PP/1RR3K1 b - - bm Nxe4; id \"STS(v5.0) Bishop vs Knight.023\";", "2r1r1k1/pp1q1pbp/2npbnp1/4p1N1/1P2P3/2P2N1P/P4PP1/R1BQRBK1 w - - bm Nxe6; id \"STS(v5.0) Bishop vs Knight.024\";", "2r2nk1/1b3ppp/p2q1n2/1p1p4/3B1P1Q/1P1NP1P1/P5BP/2R3K1 w - - bm Bxf6; id \"STS(v5.0) Bishop vs Knight.025\";", "2r2rk1/4bp2/p6p/1p1R4/3nn1p1/4P1B1/PP1NBPPP/4R1K1 b - - bm Nxe2+; id \"STS(v5.0) Bishop vs Knight.026\";", "2r2rk1/p2qbppp/5n2/3p1N2/1p2n3/1NP1BQ2/PP3PPP/R4RK1 w - - bm Nxe7+; id \"STS(v5.0) Bishop vs Knight.027\";", "2r5/2q2pk1/3n1b1p/3Pp1p1/b1B1P1N1/P4N2/5PPP/2Q2RK1 w - - bm Nxf6; id \"STS(v5.0) Bishop vs Knight.028\";", "2r5/3n2k1/5p2/Pp2nB1r/1B1pP2P/P1pP2P1/6K1/3R2R1 w - - bm Bxd7; id \"STS(v5.0) Bishop vs Knight.029\";", "2rq1rk1/1b2bppp/p3p3/n7/3P4/1BBQ1N1P/P4PP1/R3R1K1 b - - bm Nxb3; id \"STS(v5.0) Bishop vs Knight.030\";", "2rq1rk1/1p1npp1p/p2pb1p1/3N4/3QP3/1BP2P2/PP4PP/R4R1K b - - bm Bxd5; id \"STS(v5.0) Bishop vs Knight.031\";", "2rq1rk1/1p1nppbp/p2pn1p1/6B1/2P1P3/1PN1Q1PP/P4PB1/2R2RK1 b - - bm Nxg5; id \"STS(v5.0) Bishop vs Knight.032\";", "2rq1rk1/3bppbp/p4np1/n3Q3/Np6/1B3N1P/PPP2PP1/R1BR2K1 b - - bm Nxb3; id \"STS(v5.0) Bishop vs Knight.033\";", "2rq1rk1/4bppp/p1p1pn2/1p1b4/3P4/2NB1NQ1/PPP2PPP/1K1RR3 b - - bm Bxf3; id \"STS(v5.0) Bishop vs Knight.034\";", "2rq1rk1/pp1bppbp/3p1np1/8/2nNP3/1BN1BP2/PPP2QPP/R4RK1 w - - bm Bxc4; id \"STS(v5.0) Bishop vs Knight.035\";", "2rqr1k1/1b3p1p/pn1p1bpB/2p5/3P4/1P3N1P/P2QBPP1/2RR2K1 b - - bm Bxf3; id \"STS(v5.0) Bishop vs Knight.036\";", "2rqr1k1/1b3ppp/3b2n1/p2pN3/1p1P1B2/3BPP1P/P2Q2P1/1R1R2K1 b - - bm Nxf4; id \"STS(v5.0) Bishop vs Knight.037\";", "2rr2k1/ppq1pp1p/2npbnpB/8/2PNP3/1QP2P2/P3B1PP/R4RK1 w - - bm Nxe6; id \"STS(v5.0) Bishop vs Knight.038\";", "2rr4/p3q1pk/bn2p2p/2b1Pp2/1pN4P/1P4Q1/P2BBPP1/2RR2K1 b - - bm Bxc4; id \"STS(v5.0) Bishop vs Knight.039\";", "3b1k2/1b3p1p/pP4p1/3p4/1p1PnBP1/1K3B2/PP2N2P/8 w - - bm Bxe4; id \"STS(v5.0) Bishop vs Knight.040\";", "3qr2k/p5r1/1pRp1n1b/1P1Pp2p/1P3p1P/2N1nP1Q/1R3BP1/5BK1 w - - bm Bxe3; id \"STS(v5.0) Bishop vs Knight.041\";", "3r1rk1/1b2p1bp/pp6/4Pp1n/B2n4/2NNBP1p/PP3KPP/3RR3 w - - bm Bxd4; id \"STS(v5.0) Bishop vs Knight.042\";", "3r2k1/1b3ppp/1p2pq2/p7/2P5/1Pn1QNP1/4PPBP/4R1K1 b - - bm Bxf3; id \"STS(v5.0) Bishop vs Knight.043\";", "3r2k1/5p1p/p2qn1p1/P3N1r1/1P1pb1B1/2nN3P/5PPQ/2R1R2K b - - bm Bxd3; id \"STS(v5.0) Bishop vs Knight.044\";", "3r2k1/pr2bpp1/6bp/3nN3/2R3P1/4B2P/P3BP2/3R2K1 b - - bm Nxe3; id \"STS(v5.0) Bishop vs Knight.045\";", "3rk2r/1p2bp2/p1n1q2p/3pPbp1/3B4/2P3Q1/BN3PPP/R3R1K1 b k - bm Nxd4; id \"STS(v5.0) Bishop vs Knight.046\";", "3rr1k1/p1p1p1bp/2p2pp1/3bP3/5P2/BPP2N2/P5PP/4RRK1 b - - bm Bxf3; id \"STS(v5.0) Bishop vs Knight.047\";", "3rr3/p3b1kp/2p2pp1/1q1npb2/4N1PB/1NP2Q2/PP3P1P/R2R2K1 b - - bm Bxe4; id \"STS(v5.0) Bishop vs Knight.048\";", "4qr1k/2bn1p1p/2N1p3/p2nP3/NpRQ1B2/1P4PP/P6K/8 b - - bm Nxf4; id \"STS(v5.0) Bishop vs Knight.049\";", "4r1k1/p4bp1/1p1p1p2/1P1N2n1/4P1P1/4qP1P/P4RQ1/5BK1 b - - bm Bxd5; id \"STS(v5.0) Bishop vs Knight.050\";", "4r1k1/p4p1p/1p2q1pB/1Q2Pn2/P3B2P/5P2/bR3P2/6K1 w - - bm Bxf5; id \"STS(v5.0) Bishop vs Knight.051\";", "4r1k1/pb6/2pbpp1B/2N2p2/3P4/1P6/P4KPP/R7 b - - bm Bxc5; id \"STS(v5.0) Bishop vs Knight.052\";", "4r3/1p2rpk1/p1p1bqp1/2QnN1bp/1B1PB3/P6P/1P2RPP1/4R1K1 b - - bm Nxb4; id \"STS(v5.0) Bishop vs Knight.053\";", "4r3/5pkp/2b1n1p1/3p3n/p1pP4/P1N1BP1B/1P3KPP/2R5 w - - bm Bxe6; id \"STS(v5.0) Bishop vs Knight.054\";", "4rrk1/2q3pp/pp1p1bn1/2nR4/2P2B2/N4PP1/PP3Q1P/3R1BK1 b - - bm Nxf4; id \"STS(v5.0) Bishop vs Knight.055\";", "5k2/p2b3r/1ppb1p2/1q1p1P2/1P1PrNpP/4P1P1/1RQ2BK1/2R5 b - - bm Bxf4; id \"STS(v5.0) Bishop vs Knight.056\";", "5k2/p2q2p1/bp1p1p1p/3PnP1Q/1P1BP3/2P5/3N2P1/6K1 w - - bm Bxe5; id \"STS(v5.0) Bishop vs Knight.057\";", "6k1/r2rbpp1/p1q2n2/1pp2PB1/5Q2/1PN1R2P/1P3P2/4R1K1 w - - bm Bxf6; id \"STS(v5.0) Bishop vs Knight.058\";", "6k1/r6p/2pb1ppn/p1Np4/1P1PrPP1/P6P/2R5/3K1RB1 b - - bm Bxc5; id \"STS(v5.0) Bishop vs Knight.059\";", "6n1/p6k/2R5/2p1rp2/p1P1n3/P3PB1P/5PP1/6K1 w - - bm Bxe4; id \"STS(v5.0) Bishop vs Knight.060\";", "6r1/r2Nbnk1/2R3pp/p4p2/PpB2PP1/1P6/6K1/3R4 w - - bm Bxf7; id \"STS(v5.0) Bishop vs Knight.061\";", "8/1R3pp1/p3rnk1/3pBb1p/3P3P/1B1P1PP1/5K2/8 w - - bm Bxf6; id \"STS(v5.0) Bishop vs Knight.062\";", "8/5p1k/2p3pp/2p1p3/2P2nPP/2Q2P2/1P1B1K2/q7 w - - bm Bxf4; id \"STS(v5.0) Bishop vs Knight.063\";", "8/6k1/4ppp1/r2Pn2p/bpq1PB1P/6P1/R4PK1/1QN5 w - - bm Bxe5; id \"STS(v5.0) Bishop vs Knight.064\";", "8/r2b1nk1/Np1qp2p/pP1pNrpP/Pp1P4/3Q1PP1/2R3K1/7R w - - bm Nxd7; id \"STS(v5.0) Bishop vs Knight.065\";", "q1r1r1k1/p2nppbp/1pnpb1p1/6N1/1PP1P3/P1N1Q2P/4BPPB/1R1R2K1 w - - bm Nxe6; id \"STS(v5.0) Bishop vs Knight.066\";", "q5k1/1pbb2pn/2ppNr1p/p3rP2/P1P1pNB1/1P5P/5PP1/1RQR2K1 b - - bm Bxe6; id \"STS(v5.0) Bishop vs Knight.067\";", "r1b1r1k1/p1qn1ppp/2pb1n2/4pN2/Np2P3/7P/PPQ1BPP1/R1B2RK1 w - - bm Nxd6; id \"STS(v5.0) Bishop vs Knight.068\";", "r1b1r1k1/ppq2ppp/2n5/3p4/P1pPn3/B1P1PN2/2B2PPP/R2Q1RK1 w - - bm Bxe4; id \"STS(v5.0) Bishop vs Knight.069\";", "r1b2rk1/p3qppp/1pn5/2b5/3pN3/5NP1/PP2PPBP/R2Q1RK1 w - - bm Nxc5; id \"STS(v5.0) Bishop vs Knight.070\";", "r1bq2k1/pp3rbp/2n1p1p1/1BBpPn2/8/2N2N1P/PP3PP1/R2Q1RK1 w - - bm Bxc6; id \"STS(v5.0) Bishop vs Knight.071\";", "r1br4/pp3pk1/2p2npp/2n1N3/P2q4/2NB2QP/1PP2PP1/R3R1K1 b - - bm Nxd3; id \"STS(v5.0) Bishop vs Knight.072\";", "r1r3k1/1nqb1ppp/3p4/pp1Pb3/1P2Pp2/R1PB1N1P/Q4PP1/1N2R1K1 w - - bm Nxe5; id \"STS(v5.0) Bishop vs Knight.073\";", "r1r3k1/1p1b1p2/1q1p3p/1NpPb1pB/PpP1Pp2/1P6/R4PPP/1Q1R3K b - - bm Bxb5; id \"STS(v5.0) Bishop vs Knight.074\";", "r1r4k/pb1nq1pp/1p1bp3/1N1p1p2/3Pn3/1P1NB1P1/PQ2PPBP/R4RK1 w - - bm Nxd6; id \"STS(v5.0) Bishop vs Knight.075\";", "r2q1rk1/2pb2b1/1p1p2pp/p1nP1p1n/2P5/2N1B1P1/PPQ1B2P/R3NRK1 w - - bm Bxh5; id \"STS(v5.0) Bishop vs Knight.076\";", "r2q1rk1/pb3pbp/1pn1p1p1/2pnN3/2N2B2/3P2P1/PPP2PBP/R2QR1K1 b - - bm Nxf4; id \"STS(v5.0) Bishop vs Knight.077\";", "r2q1rk1/pppb1ppp/1b1p2n1/3Pp3/2N1P1n1/2PB1N2/PP3PPP/R1BQR1K1 w - - bm Nxb6; id \"STS(v5.0) Bishop vs Knight.078\";", "r2r2k1/1p2qppp/2n1bn2/p2Bp1N1/2P5/R5P1/1P1NPP1P/1Q1R2K1 w - - bm Nxe6; id \"STS(v5.0) Bishop vs Knight.079\";", "r2r2k1/1pq2pp1/p1b1p2p/3n4/8/1QB3P1/PP2PPBP/R3R1K1 b - - bm Nxc3; id \"STS(v5.0) Bishop vs Knight.080\";", "r2r2k1/ppp2pb1/2n1p1pp/1B2P3/3PNn1q/2Q1BP2/PP3P1P/2R1K2R w K - bm Bxf4; id \"STS(v5.0) Bishop vs Knight.081\";", "r3k2r/ppqbnpb1/n1p1p2p/P2pP1p1/3P4/1P1BBN1P/1NPQ1PP1/R3K2R w KQkq - bm Bxa6; id \"STS(v5.0) Bishop vs Knight.082\";", "r3kb1B/1p1b3p/pqnpp1p1/7n/8/2NRp3/PPP1B3/1K1RQ3 w q - bm Bxh5; id \"STS(v5.0) Bishop vs Knight.083\";", "r3qrk1/1pp2bp1/p1n1p2p/2Pp1pbP/1P1P4/P1NBPN2/2Q2PP1/2R1K2R w K - bm Nxg5; id \"STS(v5.0) Bishop vs Knight.084\";", "r3r1k1/p1q3bp/2p1bpp1/2nnp3/2N1N3/2PB2B1/PPQ2PPP/R3R1K1 b - - bm Nxd3; id \"STS(v5.0) Bishop vs Knight.085\";", "r3r1k1/pp3pbp/2p3p1/P3p3/1n2P1n1/2N1B3/1PPR1PPP/R3N1K1 b - - bm Nxe3; id \"STS(v5.0) Bishop vs Knight.086\";", "r3r1k1/ppq2pb1/2p1b1p1/P3n2p/2PN1B2/7P/1P1QBPP1/R2R2K1 w - - bm Nxe6; id \"STS(v5.0) Bishop vs Knight.087\";", "r3r2k/6p1/q3pp1p/1b1pn2P/3Q2B1/1P6/1BP2PP1/1K1RR3 b - - bm Nxg4; id \"STS(v5.0) Bishop vs Knight.088\";", "r3rbk1/1p3pp1/1qp1b2p/p1Nn4/2Rp4/P2P1BP1/1P1BPP1P/2Q1R1K1 b - - bm Bxc5; id \"STS(v5.0) Bishop vs Knight.089\";", "r4r1k/1p2b1pp/pBq3n1/2PNp3/2N1Ppn1/1Q4P1/PP1R3P/5RK1 w - - bm Nxe7; id \"STS(v5.0) Bishop vs Knight.090\";", "r4r2/p1n1q1bk/6pp/1pp2b2/2P1p3/P3N1P1/R2QPPBP/2BR2K1 w - - bm Nxf5; id \"STS(v5.0) Bishop vs Knight.091\";", "r4r2/p3pp1k/1nR1b2p/5Np1/4P3/5NP1/Pb3PBP/5RK1 b - - bm Bxf5; id \"STS(v5.0) Bishop vs Knight.092\";", "r4rk1/1bq2pp1/1p1bpn1p/p2nN3/P1BP4/5NP1/1P1BQPKP/R3R3 b - - bm Bxe5; id \"STS(v5.0) Bishop vs Knight.093\";", "r4rk1/1p2bppp/p2p1nn1/3P4/2PN1B2/8/PP2B1PP/R4R1K b - - bm Nxf4; id \"STS(v5.0) Bishop vs Knight.094\";", "r4rk1/1ppbq1bp/1n4p1/p1NPpp2/1n6/1PN1P1PP/PB3PB1/R2Q1RK1 w - - bm Nxd7; id \"STS(v5.0) Bishop vs Knight.095\";", "r4rk1/ppq1ppbp/1np1P1p1/2Nb4/Pn6/3B1N1P/1PP1QPP1/R1B1R1K1 b - - bm Nxd3; id \"STS(v5.0) Bishop vs Knight.096\";", "r5k1/pp1n1rpp/2pb1q2/2N5/1P3B2/P2P2P1/3Q1PKP/1R2R3 b - - bm Bxc5; id \"STS(v5.0) Bishop vs Knight.097\";", "r5k1/pp2q1bp/n2p2p1/2pPpr2/2P1Nn2/PQ3N1P/1P1B1PP1/1R2R1K1 w - - bm Bxf4; id \"STS(v5.0) Bishop vs Knight.098\";", "r6r/4bkpp/2p1np2/p1p5/2P1NB2/6P1/PP2P2P/3R1R1K b - - bm Nxf4; id \"STS(v5.0) Bishop vs Knight.099\";", "rnq1k2r/p3ppbp/1p2bnp1/2p3N1/4P3/3BB2P/P1QN1PP1/1R3RK1 w kq - bm Nxe6; id \"STS(v5.0) Bishop vs Knight.100\";", "1k1r1r2/p1p5/Bpnbb3/3p2pp/3P4/P1N1NPP1/1PP4P/2KR1R2 w - - bm Ncxd5; id \"STS(v6.0) Recapturing.001\"; ", "1k1r4/4rp2/1p1qbnp1/p2p3p/P2P4/1Nn2P2/1P1QBRPP/2R3K1 w - - bm Rxc3; id \"STS(v6.0) Recapturing.002\"; ", "1k1rr3/pp2qpp1/1b2p3/4N2p/2R1n2P/P2R2P1/1PP1QP2/1K6 w - - bm Rxe4; id \"STS(v6.0) Recapturing.003\"; ", "1k3rn1/3r1p2/p2p1np1/Pp1P3p/1Pp1PP2/2P1R1bP/2B2K1B/6R1 w - - bm Bxg3; id \"STS(v6.0) Recapturing.004\"; ", "1q2rnk1/5rb1/bp1p1np1/pNpP2Bp/P1P1Pp1P/3B2P1/3QNRR1/7K w - - bm gxf4; id \"STS(v6.0) Recapturing.005\"; ", "1q4k1/1r3pp1/3p1n1p/2pPpP2/b1PnP3/rPB1R1NP/3Q2PK/1R3B2 b - - bm Bxb3; id \"STS(v6.0) Recapturing.006\"; ", "1qr2rk1/4ppbp/6p1/pp1b4/2NP4/4B3/PPB2PPP/2RQR2K b - - bm bxc4; id \"STS(v6.0) Recapturing.007\"; ", "1qrr3k/6p1/1p1pp2p/pNn5/Pn1bP1PP/5Q2/1PP1N3/1K1R2R1 w - - bm Nexd4; id \"STS(v6.0) Recapturing.008\"; ", "1r1q2k1/5pp1/2bp2rp/p1pNp2n/2PBP3/1P1B1P2/P2Q2PP/1R3RK1 b - - bm cxd4; id \"STS(v6.0) Recapturing.009\"; ", "1r1r2k1/5pb1/6p1/p1pb2Pp/PpB1PR2/7P/1PP5/2KR4 w - - bm exd5; id \"STS(v6.0) Recapturing.010\"; ", "1r2r1k1/pb1n1pp1/1p1p2np/2P1p1q1/P1P1P3/2P2PP1/2QNBB1P/1R1R3K b - - bm Nxc5; id \"STS(v6.0) Recapturing.011\"; ", "1r2r2k/1p3pbp/b5p1/p2np3/P1P1B1PP/1PN2P2/6K1/3R1R2 w - - bm Nxd5; id \"STS(v6.0) Recapturing.012\"; ", "1r2rbk1/1b1q1p2/3pn1p1/1p5p/1p2P2P/P1P1BPP1/4QNBK/2R1R3 w - - bm axb4; id \"STS(v6.0) Recapturing.013\"; ", "1r3nk1/3r1qb1/bp1p1np1/pNpP2Bp/P1P1Pp1P/7N/1P1QBR2/6RK w - - bm Rxf4; id \"STS(v6.0) Recapturing.014\"; ", "1r3r2/1b4bk/p1n2ppp/qp1p4/4PN2/1B2B1P1/P3QP2/1R1R2K1 w - - bm exd5; id \"STS(v6.0) Recapturing.015\"; ", "1r3rk1/p1qnppbp/p5p1/2pPP3/2P5/4R2P/PP2Q1P1/1RBN3K b - - bm Bxe5; id \"STS(v6.0) Recapturing.016\"; ", "1r4k1/1rq2ppp/3p1n2/2pPp3/p1PnP3/PPB4P/3Q1PP1/1R2RBK1 b - - bm axb3; id \"STS(v6.0) Recapturing.017\"; ", "1r4k1/pr3ppp/q2p1n2/2pPp3/b1PnP3/PPB3NP/3Q1PP1/1R2RBK1 b - - bm Nxb3; id \"STS(v6.0) Recapturing.018\"; ", "1rq2rk1/4bp2/2np2p1/p1p1p3/P1PNP1P1/1PB2P2/1Q3K1P/R2R1N2 b - - bm exd4; id \"STS(v6.0) Recapturing.019\"; ", "1rq2rk1/4bp2/2np2p1/p1p1p3/P1PNP1P1/1PB2P2/1Q4P1/R2R1NK1 b - - bm cxd4; id \"STS(v6.0) Recapturing.020\"; ", "1rq2rk1/4bp2/2np2p1/p1p1p3/P1PNP1P1/1PB2P2/1Q4PK/R2R1N2 b - - bm cxd4; id \"STS(v6.0) Recapturing.021\"; ", "1rq2rk1/4bp2/3pn1p1/p1p1p3/P1PNP1P1/1PB2P2/1Q5P/R2R1NK1 b - - bm Nxd4; id \"STS(v6.0) Recapturing.022\"; ", "2kr3r/p1p4p/1np2p2/3P4/1b2N3/1P4P1/PB3PP1/R2K1R2 b - - bm Nxd5; id \"STS(v6.0) Recapturing.023\"; ", "2qr2r1/1p3pk1/p1np1np1/7p/2P1Pp2/1PN5/3QN1PP/4RR1K w - - bm Nxf4; id \"STS(v6.0) Recapturing.024\"; ", "2r1rbk1/1p3p2/1qn3p1/p1Pp1b1p/5P2/2P1RNP1/PP1Q2BP/RN5K b - - bm Bxc5; id \"STS(v6.0) Recapturing.025\"; ", "2r2r1k/1q1nbpp1/p3p2p/2P1P3/1p1N1B1P/6Q1/PP3PP1/R2R2K1 b - - bm Nxc5; id \"STS(v6.0) Recapturing.026\"; ", "2r2rk1/1p1q1pb1/p2p1np1/7p/2P1Pp1Q/1PN5/P2B2PP/4RR1K w - - bm Rxf4; id \"STS(v6.0) Recapturing.027\"; ", "2r2rk1/3bqppp/1p6/p2pb2Q/Pn1P1P2/1P2PN2/6PP/R1B2RK1 w - - bm fxe5; id \"STS(v6.0) Recapturing.028\"; ", "2r2rk1/3bqppp/2p5/p2pb2Q/Pn1P1P2/1P2PN2/6PP/R1B2RK1 w - - bm Qxe5; id \"STS(v6.0) Recapturing.029\"; ", "2r3k1/1bqnbpp1/1p2p2p/2P5/P7/4PN1B/1B2QPPP/R5K1 b - - bm Nxc5; id \"STS(v6.0) Recapturing.030\"; ", "2r3k1/1p1nqp1p/1P4p1/Q2Pp3/1RbnP3/5P1P/3N2P1/5B1K w - - bm Rxc4; id \"STS(v6.0) Recapturing.031\"; ", "2r5/4bkp1/p3q3/1b2p2n/N3PBp1/1p2Q3/1P3PPP/RB1R2K1 b - - bm Nxf4; id \"STS(v6.0) Recapturing.032\"; ", "2rq1r1k/p2nb1p1/1p3P1p/3p4/8/1P1p3Q/P2B1PPP/1R1N1RK1 b - - bm Bxf6; id \"STS(v6.0) Recapturing.033\"; ", "2rq1rk1/4ppbp/p5p1/1p1b4/1PNP4/4B3/P1B2PPP/2RQR1K1 b - - bm Rxc4; id \"STS(v6.0) Recapturing.034\"; ", "2rq1rk1/4ppbp/p5p1/1p1b4/2NP4/P3B2P/1PB2PP1/2RQR1K1 b - - bm Rxc4; id \"STS(v6.0) Recapturing.035\"; ", "2rq1rk1/4ppbp/p5p1/1p1b4/2NP4/P3B3/1P3PPP/1BRQR2K b - - bm Rxc4; id \"STS(v6.0) Recapturing.036\"; ", "2rqr1k1/1b2bp1n/1pnpp1pp/p7/P2pP2P/1NPB1NP1/1P2QPK1/1R2B1R1 w - - bm Nbxd4; id \"STS(v6.0) Recapturing.037\"; ", "2rr4/1pqb1ppk/p1Nppn1p/4n3/2P1P3/2N3P1/PP1QB1PP/R3BRK1 b - - bm Bxc6; id \"STS(v6.0) Recapturing.038\"; ", "3b2nk/p2Nqrpp/1pB1p3/3pPnp1/1P1P1P1P/P7/2R1QB1K/8 w - - bm fxg5; id \"STS(v6.0) Recapturing.039\"; ", "3q4/p2b2kp/1R1P1p2/b1p5/2B1rPp1/8/P5P1/B1Q2RK1 b - - bm Bxb6; id \"STS(v6.0) Recapturing.040\"; ", "3r1r2/pkp4p/1np1p3/3P4/1b2N3/1P3P2/1B4PP/2R2RK1 b - - bm exd5; id \"STS(v6.0) Recapturing.041\"; ", "3r1rk1/ppp2ppp/1nnN4/7q/8/1B5P/PP1BRPP1/R3Q1K1 b - - bm cxd6; id \"STS(v6.0) Recapturing.042\"; ", "3r4/pkp2r2/1np5/3P3p/1b1BN1p1/1P3PP1/6P1/2R2R1K b - - bm cxd5; id \"STS(v6.0) Recapturing.043\"; ", "3r4/pkp2r2/1np5/3P3p/1b1BN1pP/1P3P2/6P1/2R2R1K b - - bm Rxd5; id \"STS(v6.0) Recapturing.044\"; ", "3rkb1r/p2npp1p/1p4p1/1Q1p4/P2p1B2/2q1PN2/2P2PPP/R4RK1 w k - bm exd4; id \"STS(v6.0) Recapturing.045\"; ", "3rr1k1/p4bbp/1p1p4/3p1BPp/P2p1N1P/2P1P1K1/R1P5/3R4 w - - bm exd4; id \"STS(v6.0) Recapturing.046\"; ", "3rr1k1/pR1n1p1p/5b2/3N4/6p1/P2bp1P1/3N1PBP/2R3K1 w - - bm Nxe3; id \"STS(v6.0) Recapturing.047\"; ", "4q1k1/p2n1pp1/4p2p/3n4/1P1P4/P4P2/1B1QN1PP/2r2K2 w - - bm Bxc1; id \"STS(v6.0) Recapturing.048\"; ", "4r1k1/2p2rp1/1pnp4/p2N3p/2P2p2/PP1RP1P1/6KP/5R2 w - - bm gxf4; id \"STS(v6.0) Recapturing.049\"; ", "4rnk1/3r1qb1/bp1p1np1/pNpP2Bp/P1P1Pp1P/3B4/1P1QNR2/6RK w - - bm Nxf4; id \"STS(v6.0) Recapturing.050\"; ", "5r2/4k3/2qpp2b/pN2p2n/P3PR1p/2P5/6PP/QB2R2K b - - bm Bxf4; id \"STS(v6.0) Recapturing.051\"; ", "6k1/pp2npp1/2r1bq1p/3p4/PP3N1P/5BP1/4QP2/3R3K w - - bm Bxd5; id \"STS(v6.0) Recapturing.052\"; ", "6n1/1k1qn1r1/1p1p4/p1pPpPp1/2P3N1/2B2PP1/PP4Q1/KR6 b - - bm Nxf5; id \"STS(v6.0) Recapturing.053\"; ", "8/1p4k1/3p4/p1pbp1r1/P1P1P2p/1PK2B2/5R2/8 w - - bm exd5; id \"STS(v6.0) Recapturing.054\"; ", "8/p1p2p1k/1p1pqn1p/7r/P1PPP1rP/2P1RQ2/3N1K2/6R1 b - - bm Rhxh4; id \"STS(v6.0) Recapturing.055\"; ", "b2r1r2/6bk/p1n2ppp/q2p4/1p2PN2/1B2B1P1/P3QP2/1R1R2K1 w - - bm Rxd5; id \"STS(v6.0) Recapturing.056\"; ", "b2r1r2/6bk/p1n2ppp/qp1p4/4PN2/1B2B1PP/P3Q3/1R1R2K1 w - - bm Nxd5; id \"STS(v6.0) Recapturing.057\"; ", "b4r1r/3kq1p1/p1p1p1p1/NpPpPP2/1P1P2P1/4Q2p/1K5P/4R2R w - - bm fxe6+; id \"STS(v6.0) Recapturing.058\"; ", "br1r2k1/p2n1pp1/np1p4/2P1p1qp/2P1P3/P1P2PP1/2QNBB1P/2R2R1K b - - bm Naxc5; id \"STS(v6.0) Recapturing.059\"; ", "q1rb2rk/1b3ppp/2n1p2n/p1BpP3/B2P1PP1/1p2RN1P/2PN1Q2/1R4K1 w - - bm Rexb3; id \"STS(v6.0) Recapturing.060\"; ", "q1rb2rk/1b3ppp/2n1p2n/p2pP3/B2P1PP1/Bp2RN1P/1RPNQ3/6K1 w - - bm Nxb3; id \"STS(v6.0) Recapturing.061\"; ", "q2r2k1/1br1bpp1/pp3n2/2nN4/P1P4P/1P3P1B/1BQ4P/1R1RN1K1 b - - bm Nxd5; id \"STS(v6.0) Recapturing.062\"; ", "r1b2rk1/4qppp/pp6/3pb2Q/Pn1P1P2/1P2PN2/6PP/R1B2RK1 w - - bm dxe5; id \"STS(v6.0) Recapturing.063\"; ", "r1b2rk1/p3qppp/Pp6/3pb2Q/1n1P1P2/1P2PN2/1B4PP/R4RK1 w - - bm dxe5; id \"STS(v6.0) Recapturing.064\"; ", "r1b3k1/5r2/p4n1p/3q2pP/2p1p3/P1PBB3/3N1PP1/R2QK2R b KQ - bm exd3; id \"STS(v6.0) Recapturing.065\"; ", "r1bq1rk1/1p1nbppp/p3pn2/P1p5/4p3/2NP2N1/BPPB1PPP/R2Q1RK1 w - - bm dxe4; id \"STS(v6.0) Recapturing.066\"; ", "r1q1k2r/1p1nbppp/p7/3bpP2/2P1P1P1/1PN1BQ2/7P/2KR3R w kq - bm Nxd5; id \"STS(v6.0) Recapturing.067\"; ", "r1q1k2r/1p1nbppp/p7/Q2bpP2/2B1P1P1/1P2N3/PK5P/3R3R w kq - bm Qxd5; id \"STS(v6.0) Recapturing.068\"; ", "r1qr2k1/1b1nbpp1/1P6/p1B1p2p/4P3/3B3Q/2P1N1PP/RR1N3K b - - bm Nxc5; id \"STS(v6.0) Recapturing.069\"; ", "r1qr2k1/4bp1p/2p1p1p1/2pb4/PP1P1P2/3NQ3/5BPP/R2R2K1 w - - bm Nxc5; id \"STS(v6.0) Recapturing.070\"; ", "r1qr2k1/4bp2/p1p1p1p1/2pb4/PP1P1P2/3NQ3/5BPP/R2R2K1 w - - bm bxc5; id \"STS(v6.0) Recapturing.071\"; ", "r1qr2k1/p3bp1p/P1p1p1p1/2pb4/1P1P1P2/3NQ3/5BPP/R2R2K1 w - - bm dxc5; id \"STS(v6.0) Recapturing.072\"; ", "r1r2nk1/5pp1/1pnpbq2/2B5/p1P1PN1p/8/PPNR1QP1/3R1BK1 b - - bm dxc5; id \"STS(v6.0) Recapturing.073\"; ", "r1r3k1/1p2q1pp/n2pp3/pN6/2nbP1P1/P1N2Q2/1PP4P/1K1R1R2 w - - bm Rxd4; id \"STS(v6.0) Recapturing.074\"; ", "r2q1rk1/1b1pbppp/1pn1pn2/p7/P2pP3/2PB1N2/1P1NQPPP/R1B2RK1 w - - bm Nxd4; id \"STS(v6.0) Recapturing.075\"; ", "r2q1rk1/2pnbppp/p3p3/3b4/3P2P1/3QnN1P/PP1BPP2/RNR3K1 w - - bm Qxe3; id \"STS(v6.0) Recapturing.076\"; ", "r2q1rk1/p1p1n1pp/1p1p4/P2Ppb2/1PP5/4b1P1/3QNPBP/R4RK1 w - - bm fxe3; id \"STS(v6.0) Recapturing.077\"; ", "r2qk1r1/1b2bp2/3ppp1p/p1p5/2B1PP2/1nN5/PPPQ2PP/1K1R3R w q - bm axb3; id \"STS(v6.0) Recapturing.078\"; ", "r2qk1r1/1b3pb1/2pppp1p/8/2B1PP2/1nN5/PPPQ2PP/1K1R3R w q - bm Bxb3; id \"STS(v6.0) Recapturing.079\"; ", "r2qk1r1/3bbp2/3ppp2/p7/2B1PP1p/1nN5/PPPQ2PP/1K1R3R w q - bm cxb3; id \"STS(v6.0) Recapturing.080\"; ", "r2r1k2/2b1npp1/p1np3p/1p6/3P1B2/P1N4P/1PBR1PP1/3qR1K1 w - - bm Bxd1; id \"STS(v6.0) Recapturing.081\"; ", "r2r1nk1/1q2bp2/p3pnpp/2p1B3/2p5/1P2N1P1/P1QNPP1P/2R2RK1 w - - bm Ndxc4; id \"STS(v6.0) Recapturing.082\"; ", "r3b3/4kpp1/3p1n1p/5P2/1r2P1P1/1p2RN1P/2PN4/1R4K1 w - - bm Rbxb3; id \"STS(v6.0) Recapturing.083\"; ", "r3r1k1/1p3pb1/6p1/p2b2Pp/PpB1PR2/1P6/2P4P/2KR4 w - - bm Rxd5; id \"STS(v6.0) Recapturing.084\"; ", "r4r1k/p2nb1p1/1p2pPqp/3p4/P1pPn3/2P1BN1P/1QP1BPP1/R5RK b - - bm Qxf6; id \"STS(v6.0) Recapturing.085\"; ", "r4r2/5pk1/1bR1n1p1/Pp1Np2p/1P1pP3/8/5PPP/2R3K1 w - - bm Nxb6; id \"STS(v6.0) Recapturing.086\"; ", "r4rk1/1b1pq1pp/1p6/p1n1pp2/2PBN3/P3P3/1PQ1BPPP/3R1RK1 b - - bm Bxe4; id \"STS(v6.0) Recapturing.087\"; ", "r4rk1/1p1bqpp1/2p4p/3pb2Q/Pn1P1P2/1P2PN2/6PP/R1B2RK1 w - - bm Nxe5; id \"STS(v6.0) Recapturing.088\"; ", "r4rk1/1p5p/2p2p2/2P2Pp1/p5B1/PbR2n2/1P2PPKP/2R5 w - - bm Bxf3; id \"STS(v6.0) Recapturing.089\"; ", "r4rk1/3p1b2/2p2p2/1pP1pPp1/4P1B1/P1R2n2/1P3PKP/2R5 w - - bm Bxf3; id \"STS(v6.0) Recapturing.090\"; ", "r4rk1/pp1qppbp/2p1b1p1/n7/P2PpB1N/2P3P1/2P1QPBP/1R2R1K1 w - - bm Bxe4; id \"STS(v6.0) Recapturing.091\"; ", "r4rk1/ppp2ppp/1nnb4/8/1P1P3q/PBN1B2P/4bPP1/R2QR1K1 w - - bm Qxe2; id \"STS(v6.0) Recapturing.092\"; ", "r4rn1/2q2p1k/p2p2np/4pb1Q/1pP1P3/4B2P/2P3PN/3R1R1K w - - bm Rxf5; id \"STS(v6.0) Recapturing.093\"; ", "r5b1/3rn1pk/p1n4p/1p1p1p1P/3P1B2/P1N3P1/1P1R1P2/3qRBK1 w - - bm Nxd1; id \"STS(v6.0) Recapturing.094\"; ", "r5k1/5pbp/6P1/p2R4/1p5r/P5R1/1PP5/2KB4 b - - bm hxg6; id \"STS(v6.0) Recapturing.095\"; ", "r6r/ppk1npp1/1b2p2p/2pnP2P/4N3/2p2N2/PPPB1PP1/1K1RR3 w - - bm Bxc3; id \"STS(v6.0) Recapturing.096\"; ", "rn1q1rk1/1b2bppp/1p1pp1n1/pN6/P2pP3/2PB1NP1/1P2QP1P/R1B2RK1 w - - bm cxd4; id \"STS(v6.0) Recapturing.097\"; ", "rq1r2k1/pb2npbp/4pnp1/3P2N1/Q6P/1B4N1/PP3PP1/R1BR2K1 b - - bm Bxd5; id \"STS(v6.0) Recapturing.098\"; ", "rqr3k1/3bb1p1/p1n2n1p/3p1p2/1P1NpP2/2N1B2P/1PPQB1P1/1K1R3R b - - bm Bxb4; id \"STS(v6.0) Recapturing.099\"; ", "rqr3k1/4bpp1/pBbp1n1p/Pp2p3/3PPP2/2N1QNP1/1P4P1/R4R1K w - - bm fxe5; id \"STS(v6.0) Recapturing.100\"; ", "1R3b2/r4pk1/2qpn1p1/P1p1p2p/2P1P2P/5PP1/6K1/1Q1BB3 w - - bm Qb6; id \"STS(v7.0) Simplification.001\"; ", "1b4k1/6p1/pr2p2p/5p2/P2N4/P1Q1P1qP/6P1/5RK1 b - - bm Be5; id \"STS(v7.0) Simplification.002\"; ", "1k1r1b1r/ppqbnp2/4p1pp/n2pP3/2pP4/P1P3B1/1P1NBPPP/1R1QRNK1 b - - bm Nf5; id \"STS(v7.0) Simplification.003\"; ", "1nb2rk1/2p1pqb1/1r2p2p/R6P/1PBP2p1/B4NN1/5PK1/3QR3 w - - bm Rf5; id \"STS(v7.0) Simplification.004\"; ", "1nr3k1/1pr2pp1/p3bn2/P3p2p/1PP4P/3BNPP1/3RN1K1/R7 w - - bm Bf5; id \"STS(v7.0) Simplification.005\"; ", "1q1rb1k1/5p1p/p3pnpb/P1r5/2B1P3/1P3P2/2R1N1PP/R2NQ2K b - - bm Bb5; id \"STS(v7.0) Simplification.006\"; ", "1r1r2k1/2p1qpp1/pnP1b2p/1p2P3/3N4/P3P2P/1QB2PP1/3RR1K1 w - - bm Qb4; id \"STS(v7.0) Simplification.007\"; ", "1r2kbQ1/1r1q1p2/p2p2n1/6P1/N1pBP3/P1N5/1PPR4/K7 w - - bm Bg7; id \"STS(v7.0) Simplification.008\"; ", "1r2r1k1/5pp1/R2p3n/3P1P1p/2p2PP1/1qb2B1P/Q7/2BR1K2 b - - bm Bd2; id \"STS(v7.0) Simplification.009\"; ", "1r3qk1/rpb2pp1/2p2n1p/p1P1p3/P1bPP2Q/2N1PN1P/1RB3P1/1R5K w - - bm Bb3; id \"STS(v7.0) Simplification.010\"; ", "1r3rk1/1nqb1p1p/p3p1p1/1ppPb3/2P1N3/1P1Q2PP/P2B2BK/1RR5 w - - bm Bc3; id \"STS(v7.0) Simplification.011\"; ", "1r4k1/3b1pbp/R2Np1p1/4n3/1P1NP3/3BP3/4K1PP/8 w - - bm Nf3; id \"STS(v7.0) Simplification.012\"; ", "1r4k1/4qpp1/r1b4p/pp1pPB2/n1pP3P/2P2N2/R1P3P1/R3Q1K1 b - - bm Bd7; id \"STS(v7.0) Simplification.013\"; ", "1r4k1/5bpp/3b2p1/3PpqPn/1pB5/rP1NBP2/P4Q2/1K1R3R w - - bm Bc5; id \"STS(v7.0) Simplification.014\"; ", "1r4k1/pp1r1p1p/2np1np1/2q5/P3PB2/1QP2B2/5PPP/R2R2K1 w - - bm Qb5; id \"STS(v7.0) Simplification.015\"; ", "1rb1r1k1/2q1bp1p/3p1np1/p1nPp3/4P3/1PRB1N1P/3BQPP1/1R3NK1 w - - bm Be3; id \"STS(v7.0) Simplification.016\"; ", "2b1r1k1/p1B1ppbp/1p4p1/8/4n3/7P/P1RRBPP1/6K1 w - - bm Rd8; id \"STS(v7.0) Simplification.017\"; ", "2bq2k1/4pp2/p2p1n2/n1pP2p1/2P3Pp/P1Q1N2P/3NPPB1/6K1 w - - bm Be4; id \"STS(v7.0) Simplification.018\"; ", "2br3k/2pqb2r/p1n1n3/P3PQ2/1pB5/5N2/1P1N1PPP/R3R1K1 b - - bm Ncd4; id \"STS(v7.0) Simplification.019\"; ", "2q1r1k1/1p2rpp1/p1p3pb/2Pp2n1/3P1R2/1Q2P1P1/PP3NKP/2B2R2 b - - bm Ne4; id \"STS(v7.0) Simplification.020\"; ", "2r1r1k1/1bq1bpp1/pp1pp1n1/2n3P1/2P1PP1p/BPN1QB1P/P1R5/3RN1K1 w - - bm Bh5; id \"STS(v7.0) Simplification.021\"; ", "2r1r1k1/1p1bn1p1/p2Bpb1p/5p1q/P2P4/5NQP/1P2BPP1/R2R2K1 w - - bm Ne5; id \"STS(v7.0) Simplification.022\"; ", "2r1r1k1/pN2b1p1/2p4p/1p1nBp1P/3P2n1/1NP5/PP2KPP1/3R3R b - - bm Bf6; id \"STS(v7.0) Simplification.023\"; ", "2r1r1k1/pb2bp1p/8/2p1Rp1q/P1N5/6P1/2Q2P1P/3R1BK1 w - - bm Bg2; id \"STS(v7.0) Simplification.024\"; ", "2r1rk2/1p2bpp1/p4nbp/4R3/P2R1P1B/2N5/1P2B1PP/5K2 b - - bm Red8; id \"STS(v7.0) Simplification.025\"; ", "2r2n2/6k1/1pNBbb2/3p1p2/3P1P2/P4KP1/2R5/4N3 w - - bm Ne5; id \"STS(v7.0) Simplification.026\"; ", "2r2rk1/p3qp1p/2b1pp1Q/2b5/1n6/2N2NP1/1P2PPBP/R2R2K1 w - - bm Nh4; id \"STS(v7.0) Simplification.027\"; ", "2r3k1/1p1b1pb1/1qn3p1/pN1p2Pp/P3r1nP/1NP3B1/1P2BPR1/R2Q2K1 b - - bm Be5; id \"STS(v7.0) Simplification.028\"; ", "2r3k1/2q1bpp1/p1P2n1p/4pb2/8/2N1BB2/1rPR1QPP/R5K1 w - - bm Nd5; id \"STS(v7.0) Simplification.029\"; ", "2r3k1/p1q1bp1p/2p1p1p1/4P3/1p6/1P1QP1P1/PB3P1P/3R2K1 b - - bm Rd8; id \"STS(v7.0) Simplification.030\"; ", "2r3k1/p2q1pp1/2p4p/1p1p1b1n/2PP4/P1QP1PP1/3B3P/4RBK1 b - - bm Bh3; id \"STS(v7.0) Simplification.031\"; ", "2r5/4k1p1/4p2p/1pnbPp2/3B4/2P5/1PB3PP/5R1K b - - bm Be4; id \"STS(v7.0) Simplification.032\"; ", "2r5/p4k2/4bp2/Ppp3p1/4p3/B1P4r/2P2P1P/R3KNR1 w - - bm Rg3; id \"STS(v7.0) Simplification.033\"; ", "2rn4/2p1rpk1/p3n1p1/P3N1P1/BpN1b2P/1P4K1/2PR4/3R4 w - - bm Rd7; id \"STS(v7.0) Simplification.034\"; ", "2rq1rk1/pb3p1p/1p1p2p1/4p3/1PPnP3/2N2P2/P2QB1PP/2RR2K1 w - - bm Nb5; id \"STS(v7.0) Simplification.035\"; ", "2rr2k1/1p3pp1/p3b2p/3pP2Q/3B4/bqP5/1P1RB1PP/1K3R2 b - - bm Bc5; id \"STS(v7.0) Simplification.036\"; ", "3Q4/2p2k1p/p3b1p1/2p3P1/4Pq2/1P2NP2/P5K1/8 w - - bm Nc4; id \"STS(v7.0) Simplification.037\"; ", "3br1k1/r4pp1/p1qpbn1p/n1p1pN2/P1B1P3/2PPN2P/3BQPP1/R4RK1 w - - bm Bd5; id \"STS(v7.0) Simplification.038\"; ", "3qr3/2n1rpbk/3p2np/R1pP2p1/P3P3/2N2P1P/2QB2P1/1R3B1K w - - bm Nb5; id \"STS(v7.0) Simplification.039\"; ", "3r1r2/1p2k1pp/p2ppn2/4n3/P3P3/1BN4P/1PP2RP1/5R1K b - - bm Nfd7; id \"STS(v7.0) Simplification.040\"; ", "3r1rk1/4q1pp/1pb1p3/p1p1P3/P3pP2/1P2P3/4Q1PP/N2R1RK1 b - - bm Rd3; id \"STS(v7.0) Simplification.041\"; ", "3r2k1/1R3ppp/8/p1p1r3/4n3/4P2P/PP2BP2/1K5R w - - bm Rd1; id \"STS(v7.0) Simplification.042\"; ", "3r2k1/1b3qp1/pp2p1p1/4P1P1/2PN1P1P/b1NR2K1/P3Q3/8 w - - bm Nc2; id \"STS(v7.0) Simplification.043\"; ", "3r2k1/1p3ppp/p3nn2/Qbp4r/2N5/1B3PP1/PP3RKP/8 w - - bm Rd2; id \"STS(v7.0) Simplification.044\"; ", "3r2k1/2rq2pp/4bp2/p1p1pn2/1n2N3/B2PP1P1/1R1Q1P1P/1R3BK1 b - - bm Nd6; id \"STS(v7.0) Simplification.045\"; ", "3r3k/p3bppp/4q3/2p1P1Bb/3p4/P6P/1P1Q1PP1/1B2R1K1 w - - bm Ba2; id \"STS(v7.0) Simplification.046\"; ", "3r4/1R4bk/7p/p3p2p/3rP3/3p3Q/P1qN1PP1/1R4K1 b - - bm Rb4; id \"STS(v7.0) Simplification.047\"; ", "3rr3/1k3p1p/p2P1np1/8/pn6/1bN1NP2/1P1RBKPP/7R w - - bm Bd1; id \"STS(v7.0) Simplification.048\"; ", "4qnk1/1p1rbppb/4p2p/1P2P2P/3N1P2/2Q2BP1/5BK1/2R5 w - - bm Qc8; id \"STS(v7.0) Simplification.049\"; ", "4r1k1/1p1n1p1b/2n2q2/2P4p/1PBp1PpN/6P1/3Q2P1/3R1NK1 w - - bm Bd3; id \"STS(v7.0) Simplification.050\"; ", "4r1k1/2R3p1/p4qnp/8/2P2p2/1Pn2Q2/5BPP/5N1K b - - bm Ne4; id \"STS(v7.0) Simplification.051\"; ", "4r1k1/4bp1p/p4np1/1r1p4/2NP1B1P/P7/1P3PP1/3RR1K1 w - - bm Bg5; id \"STS(v7.0) Simplification.052\"; ", "4r1k1/p2n3p/1qp3p1/3rp3/6P1/2B1R3/PP2Q2P/4R2K b - - bm Qb5; id \"STS(v7.0) Simplification.053\"; ", "4r1k1/p6p/2pB2pb/3pP1q1/8/1P5b/P1P2Q1P/3BR2K b - - bm Qd2; id \"STS(v7.0) Simplification.054\"; ", "4r1k1/pp3p2/2n1r1p1/2q4p/n3p3/4B1Q1/P1PRBPPP/3R2K1 b - - bm Qe5; id \"STS(v7.0) Simplification.055\"; ", "4r3/q4pkp/2p1bnp1/p3p3/PbP1P2P/4NNP1/1RQ2P2/5BK1 b - - bm Ng4; id \"STS(v7.0) Simplification.056\"; ", "4rb1k/3q1p2/2R4p/1P1npN2/4Q3/7P/1P3PP1/6K1 b - - bm Re6; id \"STS(v7.0) Simplification.057\"; ", "4rk2/1b2rqb1/p4p2/1p1P1Pp1/2pRp1N1/P1N1R1PQ/1P4P1/6K1 w - - bm Nh6; id \"STS(v7.0) Simplification.058\"; ", "5k2/1p1n1pp1/p5bp/P2p4/1P1N4/2P2PP1/4QK1P/2q2B2 w - - bm Qe3; id \"STS(v7.0) Simplification.059\"; ", "5k2/3q1pp1/pB6/4b2p/4N3/2N3P1/BP3P1P/6K1 b - - bm Bd4; id \"STS(v7.0) Simplification.060\"; ", "5k2/4rpp1/pp6/4b2p/4N1q1/2NRB1P1/BP3P1P/6K1 b - - bm Rd7; id \"STS(v7.0) Simplification.061\"; ", "5r1k/2q2rpp/2BbRn2/p1pP1P2/1p1p2PB/1P1P1Q1P/6K1/R7 w - - bm Bg3; id \"STS(v7.0) Simplification.062\"; ", "5r2/6pk/5qnp/4p3/2QpP3/P2R1NP1/1r3P1P/2R3K1 b - - bm Nf4; id \"STS(v7.0) Simplification.063\"; ", "5rk1/2p1q2p/1r2p2Q/3nNp2/8/6P1/1P3P1P/2RR2K1 w - - bm Rc6; id \"STS(v7.0) Simplification.064\"; ", "5rk1/p3qp1p/2r1p2Q/2b2p2/1n5N/2N3P1/1P2PP1P/R2R2K1 w - - bm e4; id \"STS(v7.0) Simplification.065\"; ", "5rk1/pb2qppp/1p2p3/7B/2P5/1P4QP/P4PP1/3R2K1 w - - bm Qd6; id \"STS(v7.0) Simplification.066\"; ", "6bk/6p1/1b1q2n1/p6p/3N4/1P1Q4/P4PPP/3R2K1 w - - bm Nf3; id \"STS(v7.0) Simplification.067\"; ", "6k1/p4ppp/4p3/3n4/8/1Pn1PP1P/P3b1P1/R1B3K1 w - - bm Bd2; id \"STS(v7.0) Simplification.068\"; ", "6k1/pp3p1p/1q2r1p1/3p4/6n1/6P1/PPPQ1P1P/3R1BK1 w - - bm Qd4; id \"STS(v7.0) Simplification.069\"; ", "6rk/2R4p/Pp1pq3/1P2pp2/1P2b3/8/6PP/2Q2BK1 w - - bm Qc4; id \"STS(v7.0) Simplification.070\"; ", "7k/4r1p1/1p1b3p/p4q2/8/P5PP/1P1NQPK1/4R3 w - - bm Qf3; id \"STS(v7.0) Simplification.071\"; ", "7r/2q2pkp/2b1n1pN/3pP3/2pP4/4Q2P/2B2PP1/R5K1 w - - bm Bf5; id \"STS(v7.0) Simplification.072\"; ", "7r/p1P2kb1/1nB1b3/6pp/4p3/2P3BP/PP3PP1/R5K1 b - - bm Nd5; id \"STS(v7.0) Simplification.073\"; ", "8/p4k2/1p3r2/2pPnb2/2Pr3P/PPK3P1/4B1Q1/8 b - - bm Bg4; id \"STS(v7.0) Simplification.074\"; ", "b5k1/q4p1p/3p1bp1/4p3/1NB1P3/3P3P/1Q3PP1/6K1 w - - bm Bd5; id \"STS(v7.0) Simplification.075\"; ", "b7/3r2bk/p2Np1p1/2B1p1Pp/qP2P2P/P2Q1RK1/8/8 w - - bm Rf7; id \"STS(v7.0) Simplification.076\"; ", "q1rr2k1/pbnn1pbp/1p4p1/4p1P1/2P1P3/1NN2B2/PP2QB1P/3RR1K1 w - - bm Bg4; id \"STS(v7.0) Simplification.077\"; ", "r1b2kr1/pp1nbp2/4pn1p/2q3p1/B1P5/P1B2N1P/1P2QPP1/3R1KNR w - - bm Ne5; id \"STS(v7.0) Simplification.078\"; ", "r1b2rk1/1p2Bpbp/1np3p1/4P3/pn6/1N3N1P/1P1RBPP1/R5K1 b - - bm Nc2; id \"STS(v7.0) Simplification.079\"; ", "r1b2rk1/p1qn1ppp/2pb1n2/8/Np1NP3/7P/PPQ1BPP1/R1B2RK1 w - - bm Nf5; id \"STS(v7.0) Simplification.080\"; ", "r1b2rk1/pp1p1ppp/4pn2/6q1/2PP4/P1N5/1PQ2PPP/R3KB1R w KQ - bm Qd2; id \"STS(v7.0) Simplification.081\"; ", "r1bR4/1p3pkp/1np3p1/4P3/pB6/1n3N1P/1P2BPP1/6K1 b - - bm Be6; id \"STS(v7.0) Simplification.082\"; ", "r1bq1rk1/pp2ppbp/1n1n2p1/2p5/5B2/1PN2NP1/P1Q1PPBP/3R1RK1 w - - bm Nb5; id \"STS(v7.0) Simplification.083\"; ", "r1bq2k1/ppbnr1p1/2p1ppBp/2Pp4/P2P3N/2Q5/1P1B1PPP/4RRK1 b - - bm Nf8; id \"STS(v7.0) Simplification.084\"; ", "r1q2r1k/1bBnbpp1/4p2p/pN1p3P/8/5BQ1/PPP2PP1/1K1R3R b - - bm Bc6; id \"STS(v7.0) Simplification.085\"; ", "r2q1r1k/ppp3bp/3pb3/6p1/2Pn4/1PN3BP/P2QBPP1/3RR1K1 w - - bm Bg4; id \"STS(v7.0) Simplification.086\"; ", "r2q1rk1/1p3pp1/6p1/3Bn3/Ppp1P1P1/1n3P2/1P5P/1RBQ1RK1 w - - bm Bf4; id \"STS(v7.0) Simplification.087\"; ", "r2r2k1/1q3pbp/p3b3/2pPN3/2p1RB2/7P/PP3PP1/R2Q2K1 w - - bm Nc6; id \"STS(v7.0) Simplification.088\"; ", "r2r2k1/p2bppbp/1p4p1/2pP4/2q1P3/2P1B3/P1QN1PPP/2R2RK1 b - - bm Qa4; id \"STS(v7.0) Simplification.089\"; ", "r2r4/5kpp/p2q1n2/1p4B1/3b4/2Np1Q2/PP3PPP/3R1RK1 w - - bm Ne4; id \"STS(v7.0) Simplification.090\"; ", "r3k1r1/2q1bp2/2p1p1np/p1Pp2P1/Pp1Pn2P/1P2P3/1B2NNP1/R3QRK1 b q - bm Ng3; id \"STS(v7.0) Simplification.091\"; ", "r3kb1r/3n1ppp/p3p3/3bP3/Pp6/4B3/1P1NNPPP/R4RK1 w kq - bm Nf4; id \"STS(v7.0) Simplification.092\"; ", "r3nbk1/1b3ppp/pr6/1pp1PBq1/P1P5/7P/1B1NQPP1/R3R1K1 w - - bm Be4; id \"STS(v7.0) Simplification.093\"; ", "r3r1k1/2q2np1/3p1pNp/p2P4/R4PP1/2P3K1/1P1Q4/7R w - - bm Re1; id \"STS(v7.0) Simplification.094\"; ", "r3r1k1/5pp1/p1n2q1p/P1bp1P2/2p2P2/5N2/2BB3P/R2QRK2 b - - bm Nd4; id \"STS(v7.0) Simplification.095\"; ", "r4bk1/1p1nqp1p/p1p1b1p1/P3p3/2P1P3/1QN2PP1/1P5P/R4BBK b - - bm Qb4; id \"STS(v7.0) Simplification.096\"; ", "r4rk1/2pqbppp/p1n5/1p1pP3/3P4/1B2Bb1P/PP1Q1PP1/R1R3K1 w - - bm Qc3; id \"STS(v7.0) Simplification.097\"; ", "r7/4pp1k/6pb/p1rPp2p/2P1P2q/7P/1RQ1BPP1/1R4K1 w - - bm Rb5; id \"STS(v7.0) Simplification.098\"; ", "rn3rk1/pp1q2bp/3ppnp1/2p3N1/2P1P3/8/PP2NPPP/R1BQ1RK1 w - - bm e5; id \"STS(v7.0) Simplification.099\"; ", "rq4k1/1b1nbpp1/4p2p/r1PnP3/Np6/1P1B1N2/1Q1B1PPP/R2R2K1 b - - bm Bc6; id \"STS(v7.0) Simplification.100\"; ", "1qr2k1r/pb3pp1/1b2p2p/3nP3/1p6/3B2QN/PP3PPP/R1BR2K1 b - - bm g5; id \"STS(v8.0) AKPC.001\"; ", "1r1qr1k1/p5b1/2p2ppp/3p4/1Pp5/P1Nn1Q2/3BN1PP/R4RK1 b - - bm f5; id \"STS(v8.0) AKPC.002\"; ", "1r1rq1k1/1p4p1/pNb1pp1p/1pP5/3P4/1PQ5/5PPP/R3R1K1 w - - bm f3; id \"STS(v8.0) AKPC.003\"; ", "1r3r2/1p3q1k/1Q1p4/2pNbpp1/2P5/7P/PP2R1P1/3R3K b - - bm f4; id \"STS(v8.0) AKPC.004\"; ", "1r4k1/2p2p1p/4n1p1/2qpP3/2nN4/1BPQ4/Pr3PPP/3RR1K1 w - - bm h4; id \"STS(v8.0) AKPC.005\"; ", "1r4k1/3q2pp/2np4/2p1pp2/2P1P3/R1BP1Q1P/5PP1/6K1 b - - bm f4; id \"STS(v8.0) AKPC.006\"; ", "1r4k1/ppq2ppp/r4nn1/P2p4/2pP4/B1P1P1PP/1Q1N1PK1/RR6 b - - bm h5; id \"STS(v8.0) AKPC.007\"; ", "1rb1r1k1/4qpb1/p1np1npp/1pp5/2P1PN2/1P3PP1/PB4BP/1QRR1N1K b - - bm g5; id \"STS(v8.0) AKPC.008\"; ", "1rq1n3/2pr3k/2n1bppp/p1PNp3/Pp2P3/1P2Q1PP/3R1PBK/3RN3 w - - bm f4; id \"STS(v8.0) AKPC.009\"; ", "2b2kn1/5ppQ/1r5p/p2pN3/1qpP1PP1/5P2/P6P/1B4RK w - - bm g5; id \"STS(v8.0) AKPC.010\"; ", "2qn4/p5k1/1p1Qbpp1/1B1p3p/3P3P/2P5/P4PP1/4N1K1 w - - bm g3; id \"STS(v8.0) AKPC.011\"; ", "2r1r1k1/p2b2bp/1pn1p1pq/4Pp2/2BP4/P4N2/1P2NQPP/2R2RK1 w - - bm h4; id \"STS(v8.0) AKPC.012\"; ", "2r2bk1/p1q2p2/4p1p1/3nP1B1/1p2Q2P/1P3N2/Pr3PP1/R4RK1 w - - bm h5; id \"STS(v8.0) AKPC.013\"; ", "2r2k1r/1q1nbpp1/p2p4/1p1Pp3/8/P1B2BP1/1PP1QP2/3RR1K1 b - - bm g6; id \"STS(v8.0) AKPC.014\"; ", "2r2rk1/1b1qb1pp/p2p4/1p1PpP2/4Q3/1P2BN1P/P4PP1/R3R1K1 w - - bm g4; id \"STS(v8.0) AKPC.015\"; ", "2r2rk1/2qbnppp/1p2p3/p2pPn2/P5QP/2PB1N2/2PB1PP1/1R2R1K1 w - - bm h5; id \"STS(v8.0) AKPC.016\"; ", "2r2rk1/p3ppbp/1pnp1np1/4q3/2P1P3/PPN1B2P/2Q1BPP1/R2R2K1 w - - bm f4; id \"STS(v8.0) AKPC.017\"; ", "2r2rk1/p4qb1/1p1ppp2/2n1n1pp/2PN4/1PN2PPP/P1QBP1K1/2RR4 w - - bm f4; id \"STS(v8.0) AKPC.018\"; ", "2r2rk1/pq2ppbp/1pnp1np1/8/2P1P3/2N1BP2/PPQ1BPKP/3R1R2 w - - bm f4; id \"STS(v8.0) AKPC.019\"; ", "2r3k1/p3np1p/1p1pp1p1/4b3/1PP5/P3B2P/2R2PP1/3R3K w - - bm g4; id \"STS(v8.0) AKPC.020\"; ", "2r3k1/pp2p1b1/q2pP1p1/3pnrPp/P7/1P5P/2PB1PB1/2RQR1K1 w - - bm f4; id \"STS(v8.0) AKPC.021\"; ", "2r5/1bq3kp/4pNp1/3pP1Q1/2pP4/7P/5PP1/R5K1 w - - bm h4; id \"STS(v8.0) AKPC.022\"; ", "2r5/5k2/p1n3p1/P1Pqpp1p/3n4/4BPQN/6PP/3R3K w - - bm f4; id \"STS(v8.0) AKPC.023\"; ", "2rr1bk1/p4pp1/1p2q2p/1PpN4/2Q1P3/P4PP1/3R3P/3R2K1 w - - bm f4; id \"STS(v8.0) AKPC.024\"; ", "2rr2k1/5ppp/p3p3/1p2P3/1Pn5/2B1PqP1/P1Q2P1P/3RR1K1 b - - bm h5; id \"STS(v8.0) AKPC.025\"; ", "3bn1k1/1bq1npp1/3p3p/1p1Pp3/1Pp1P3/2P1B1NP/2BN1PPK/Q7 b - - bm f5; id \"STS(v8.0) AKPC.026\"; ", "3q1r2/2r2ppk/5b1p/2pBpR2/P3P2P/1P4PK/5Q2/5R2 w - - bm g4; id \"STS(v8.0) AKPC.027\"; ", "3q2k1/rb1r3p/6p1/pQRp1p2/3N3P/1P2PBP1/P4P2/6K1 w - - bm h5; id \"STS(v8.0) AKPC.028\"; ", "3q3k/3r1p1p/4p3/p4p2/PbP2Q1P/1p3N2/1P2KPP1/1R6 b - - bm f6; id \"STS(v8.0) AKPC.029\"; ", "3q3k/5p1p/3rp3/p4p1P/PbP2Q2/1p3N2/1P2KPP1/1R6 b - - bm f6; id \"STS(v8.0) AKPC.030\"; ", "3qr1k1/5r1p/p1p1n1p1/Ppp1Q3/4Pp2/1P1P1N1P/2P2RPK/R7 b - - bm g5; id \"STS(v8.0) AKPC.031\"; ", "3qrr1k/pp1n1ppp/2n3b1/2p5/3Pp1P1/P1P1P2P/BB2QPN1/2RR2K1 b - - bm f5; id \"STS(v8.0) AKPC.032\"; ", "3r1r1k/1p2q2b/p1p1p2p/2P1P3/PPQP1pPP/5B2/7K/4BR2 b - - bm h5; id \"STS(v8.0) AKPC.033\"; ", "3r1rk1/pb1pb2p/1p2p1q1/1N2npp1/B1P5/4PPN1/PP2Q1PP/3R1RK1 b - - bm h5; id \"STS(v8.0) AKPC.034\"; ", "3r1rk1/pb2bppp/1pp1p3/2n1P2Q/2P1P3/1Pp2NP1/P4PBP/2R3K1 b - - bm g6; id \"STS(v8.0) AKPC.035\"; ", "3r2k1/2q1rp2/4p1p1/2p1P2p/1p3Q2/1P1bP1PP/P4RBK/2R5 w - - bm g4; id \"STS(v8.0) AKPC.036\"; ", "3r2k1/3n1p1p/p1r3p1/q1P3Q1/P5B1/2R1B2P/5PP1/6K1 b - - bm h6; id \"STS(v8.0) AKPC.037\"; ", "3r2k1/p1r3pp/Q1p1pb2/2Pn1p1q/PpBPp3/1P2P1PP/1B2RPK1/4R3 b - - bm g5; id \"STS(v8.0) AKPC.038\"; ", "3r2r1/2qb2pk/1p2p2p/p1n1Pp2/P1PNpP2/1P2Q3/3RB1PP/3R2K1 b - - bm g5; id \"STS(v8.0) AKPC.039\"; ", "3r4/1pq3kp/2pp1pp1/p1n1r3/P1PNP3/1P2BPPB/2Q1N1K1/8 w - - bm f4; id \"STS(v8.0) AKPC.040\"; ", "3rb1k1/2q1b1p1/pp2p3/5p1p/1PP1p3/P3Q1PP/4P1RK/3N1R2 b - - bm h4; id \"STS(v8.0) AKPC.041\"; ", "3rb1k1/2q1b1pp/pp2p3/5p2/1PP1p3/P3Q1PP/4PR1K/3N1R2 b - - bm h5; id \"STS(v8.0) AKPC.042\"; ", "3rrk2/p2n1p1B/1pq4p/2ppB1p1/2bP4/PnN1PP2/1PQ3PP/3RR1K1 w - - bm f4; id \"STS(v8.0) AKPC.043\"; ", "4b1k1/pp1qbpp1/4p3/4Q2p/8/2P1N1P1/PP3PBP/6K1 b - - bm h4; id \"STS(v8.0) AKPC.044\"; ", "4qr1k/p4n1p/1p1p2p1/2pQ1n2/2P1NB2/P1P2P2/5KPP/3R4 w - - bm g4; id \"STS(v8.0) AKPC.045\"; ", "4r1k1/p4bpp/1p6/1P6/2PQ4/4rPq1/PR2PRB1/6K1 b - - bm h5; id \"STS(v8.0) AKPC.046\"; ", "4r2k/6p1/2b2p2/pq5p/r2P2P1/2P1N1PP/B2Q1K2/4R3 b - - bm h4; id \"STS(v8.0) AKPC.047\"; ", "4r3/2pq1pk1/1r4p1/p2pP1Np/1pnP4/2PQ3P/P3RPP1/4R1K1 w - - bm f4; id \"STS(v8.0) AKPC.048\"; ", "4r3/p4rk1/1p4p1/3Rp1q1/4P2p/2Q2P2/P5PP/3R1K2 w - - bm h3; id \"STS(v8.0) AKPC.049\"; ", "4rr1k/1pq3bp/p1b2np1/P1Ppp3/1P1N2P1/1B3PB1/Q6P/3RR1K1 b - - bm h5; id \"STS(v8.0) AKPC.050\"; ", "4rr1k/2q5/1pnn1b1p/p1p2b2/N1PppPp1/PP1P4/2QBPPBP/3R1RNK b - - bm h5; id \"STS(v8.0) AKPC.051\"; ", "5k1r/1b2rp2/pR4pp/1p3n2/2p5/2N5/PP3PPP/3Q2K1 w - - bm f3; id \"STS(v8.0) AKPC.052\"; ", "5k2/q7/2p2pp1/4p1pn/1pP1PnN1/1P2RPPP/3r1B1K/5Q2 b - - bm f5; id \"STS(v8.0) AKPC.053\"; ", "5r1k/2qb1ppp/6nb/3B4/pp1BQ3/5NP1/P1P2P1P/4R1K1 w - - bm h4; id \"STS(v8.0) AKPC.054\"; ", "5r1k/2qb1ppp/6nb/3B4/ppPBQ3/5NP1/P4P1P/4R1K1 w - - bm h4; id \"STS(v8.0) AKPC.055\"; ", "5r2/3br1kp/3q2p1/1pNp4/1P1Pnp2/5B2/2P1R1PP/2Q2RK1 b - - bm g5; id \"STS(v8.0) AKPC.056\"; ", "5rk1/2r1bpp1/p2p1n1p/1p2pP2/1P3q2/1BP4P/PB3PP1/R2QR1K1 w - - bm g4; id \"STS(v8.0) AKPC.057\"; ", "5rk1/5p2/pnB1p1pp/q3P3/2nP1P2/1R1N3P/6PK/2Q5 w - - bm f5; id \"STS(v8.0) AKPC.058\"; ", "5rk1/p1r3pp/1p2q3/1P1p4/1QnB2P1/2R1PP1P/4R1K1/8 b - - bm h5; id \"STS(v8.0) AKPC.059\"; ", "6k1/2qn3p/pp1pprpB/5r2/1PP5/P4PbP/3QB1P1/2R2RK1 w - - bm f4; id \"STS(v8.0) AKPC.060\"; ", "6k1/5p1p/1p1n2pP/1n6/q1rP4/2pQP3/r1N2PP1/BRR3K1 b - - bm f5; id \"STS(v8.0) AKPC.061\"; ", "6k1/p2nqpp1/Qp2p2p/8/3PNb2/P4N2/1Pr2PPP/4R1K1 w - - bm g3; id \"STS(v8.0) AKPC.062\"; ", "8/3qpk2/1p3r1p/p1pPRp2/2P2P2/P4KPP/4Q3/8 w - - bm g4; id \"STS(v8.0) AKPC.063\"; ", "8/3r1pk1/p1pqp1p1/8/P1Pb4/5RPP/2Q5/4R2K b - - bm f5; id \"STS(v8.0) AKPC.064\"; ", "8/6pk/p5rp/2NpPq2/2bPp2b/P3P1P1/6Q1/1R2B1K1 b - - bm h5; id \"STS(v8.0) AKPC.065\"; ", "b4rk1/2pq1pp1/3p3p/B1p5/2PpP1n1/3P2P1/PR1Q1PBP/6K1 b - - bm f5; id \"STS(v8.0) AKPC.066\"; ", "b4rk1/p2q1pp1/3p3p/B1p5/2PpP1n1/P2P2P1/1R1Q1PBP/6K1 b - - bm f5; id \"STS(v8.0) AKPC.067\"; ", "b5k1/6bp/3qp1p1/3n2P1/5P1K/2rBB3/6NP/3R1Q2 b - - bm h6; id \"STS(v8.0) AKPC.068\"; ", "n1rr2k1/3qppbp/p1nP2p1/6P1/5P1Q/1P2B3/P4PBP/2RR2K1 w - - bm f5; id \"STS(v8.0) AKPC.069\"; ", "nr4k1/1p1qrpb1/p6p/P2p2p1/1P1N4/4B1P1/2RQ1PKP/2R5 w - - bm h4; id \"STS(v8.0) AKPC.070\"; ", "q5k1/4bpp1/r3p2p/2p5/1pP5/1P3NPP/1RQ1PP2/6K1 b - - bm f5; id \"STS(v8.0) AKPC.071\"; ", "r1b1r1k1/1p1nqpbp/2ppn1p1/1P6/2P1P3/2N1BPP1/2Q1N1BP/1R1R2K1 w - - bm f4; id \"STS(v8.0) AKPC.072\"; ", "r1b2rk1/1pp1q1b1/2nppn1p/pN3pp1/2PP4/1Q4PN/PP2PPBP/R1BR2K1 w - - bm f4; id \"STS(v8.0) AKPC.073\"; ", "r1b2rk1/p4pp1/1q2p2p/1p1n4/3b2N1/3B2Q1/PPP2PPP/R1B2RK1 b - - bm f5; id \"STS(v8.0) AKPC.074\"; ", "r1b2rk1/pp2qppp/n2p4/2pPp3/P1N1P3/3P4/1P2BPPP/R1Q2RK1 w - - bm f4; id \"STS(v8.0) AKPC.075\"; ", "r1b2rk1/pp3pp1/1q2p2p/3n4/3b2N1/3B2Q1/PPP2PPP/R1B2RK1 b - - bm h5; id \"STS(v8.0) AKPC.076\"; ", "r1b4r/pp3k1p/3R1p2/B1p5/2P4Q/5q2/PP2NP1P/2K5 b - - bm h5; id \"STS(v8.0) AKPC.077\"; ", "r1q1k2r/3n3p/p5p1/1pbpP3/2p2P2/8/PPB1QP1P/R1B2RK1 w kq - bm f5; id \"STS(v8.0) AKPC.078\"; ", "r1q2rk1/p3npb1/1pnBb1pp/2p1P3/8/2N2NPP/PP2QPB1/R4RK1 w - - bm g4; id \"STS(v8.0) AKPC.079\"; ", "r1r3k1/1bqn1pbp/pp1pp1p1/4n3/2P2N1P/1PN1PP2/P2BB1P1/2R1QRK1 w - - bm h5; id \"STS(v8.0) AKPC.080\"; ", "r2q1rk1/1p2n1bp/p1npp1p1/2p1p3/4P3/N1PPB1PP/1P3PB1/R2QR1K1 w - - bm h4; id \"STS(v8.0) AKPC.081\"; ", "r2q1rk1/1p2p3/2p2ppp/p2n1b2/P2P4/1B3N1P/1PP2PP1/R2QR1K1 b - - bm g5; id \"STS(v8.0) AKPC.082\"; ", "r2r2k1/1p3p1p/1qbppQp1/p7/4P3/P1NR4/1P3PPP/1R4K1 w - - bm h4; id \"STS(v8.0) AKPC.083\"; ", "r2r2k1/2pq1pp1/p1p2b1p/5p2/P2P4/2N3P1/1PQ1PP1P/R2R2K1 b - - bm f4; id \"STS(v8.0) AKPC.084\"; ", "r2r2k1/pp1qppbp/2p1bnp1/4B3/3P2P1/4QN1P/PP2PPB1/R1R3K1 b - - bm h5; id \"STS(v8.0) AKPC.085\"; ", "r3k3/1p1n1p2/2p1r1p1/3bP3/3P3Q/8/p1B2PPP/R5K1 w q - bm f4; id \"STS(v8.0) AKPC.086\"; ", "r3qrk1/1p4bp/1n1p1p1n/pPpPp1p1/P3P3/1P1N3P/3B1PP1/2QBRRK1 w - - bm h4; id \"STS(v8.0) AKPC.087\"; ", "r3qrk1/2p3pp/np6/3pN3/p2P4/P5P1/1PQ1PP2/3R1RK1 w - - bm f4; id \"STS(v8.0) AKPC.088\"; ", "r3r1k1/1pq4p/p2b1pp1/3pnb2/3N3Q/2P5/PP1B1PPP/R3RBK1 b - - bm g5; id \"STS(v8.0) AKPC.089\"; ", "r3r1k1/4qpp1/2p5/p1ppP2p/6P1/1PQ2P1P/P1P5/3RR1K1 w - - bm f4; id \"STS(v8.0) AKPC.090\"; ", "r3r1k1/pn1bnpp1/1p2p2p/1q1pP3/2pP1P1N/B1P2BP1/2P3QP/R4RK1 w - - bm f5; id \"STS(v8.0) AKPC.091\"; ", "r3rb2/1p3k2/p1p2p2/2q2bpp/2PR4/1PQ4P/P4PPB/3R1BK1 b - - bm h4; id \"STS(v8.0) AKPC.092\"; ", "r4k2/1b1qbp2/2pnp1r1/pp2B2p/2pPP1pP/P1N2P2/1P2B1PQ/2RR2K1 b - - bm f5; id \"STS(v8.0) AKPC.093\"; ", "r4rk1/1b3pbp/1qp1p1p1/p2n2B1/3P3P/P2B1N2/1PQ2PP1/R3R1K1 w - - bm h5; id \"STS(v8.0) AKPC.094\"; ", "r4rk1/1p1qn1bp/p1npp1p1/2p1p3/4P2P/N1PPB1P1/1P3PB1/R2QR1K1 w - - bm h5; id \"STS(v8.0) AKPC.095\"; ", "r4rk1/1p2qppp/1np5/p2pNb2/P2Pn3/2NBP3/1PQ2PPP/2R2RK1 b - - bm f6; id \"STS(v8.0) AKPC.096\"; ", "r4rk1/1pq1p3/2p2ppp/p2n1b2/P2P4/1B3N1P/1PP2PP1/R2QR1K1 b - - bm g5; id \"STS(v8.0) AKPC.097\"; ", "r4rk1/3n1pbp/3Pq1p1/4p3/p7/2Q1B1N1/P2R1PPP/2R3K1 b - - bm f5; id \"STS(v8.0) AKPC.098\"; ", "r4rk1/ppp1qp1p/2p3p1/4n3/4P2P/2N1QP2/PPP2P2/2KR3R w - - bm h5; id \"STS(v8.0) AKPC.099\"; ", "r5k1/p2b1r2/1p1p1q2/2pPbp1p/P1P1p3/1P4P1/2RQNPBP/4R1K1 b - - bm h4; id \"STS(v8.0) AKPC.100\"; ", "1b2r1k1/1bqn1pp1/p1p4p/Pp2p3/1P2B3/2B1PN1P/5PP1/1Q1R2K1 b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.001\"; ", "1k4nr/pppr1q2/3p2p1/3Nn1Qp/2P1PN2/1P6/P1P3PR/2KR4 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.002\"; ", "1n4k1/2pb2q1/1p1p3p/3P1p2/1PP1pP2/3rN3/4N1PP/1RQ3K1 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.003\"; ", "1nr5/p2p1qpk/1pb1p2p/5p1P/1PP2N2/P3PPQ1/6P1/3RKB2 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.004\"; ", "1q2r1k1/1b2bpp1/p2ppn1p/2p5/P3PP1B/2PB1RP1/2P1Q2P/2KR4 b - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.005\"; ", "1q2rb2/3b1r1k/p1p4p/B3p1p1/1PPpN3/3P1P1P/3QR1P1/4R1K1 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.006\"; ", "1r1qr1k1/1p3pp1/p1n1bn1p/2NN4/4P3/6P1/PP3PB1/2RQR1K1 w - - bm b3; id \"STS(v9.0) Advancement of a/b/c pawns.007\"; ", "1r1r1bk1/1bq2ppp/pnp1p3/4P3/5P2/P1NBB3/1P4PP/R1QR2K1 b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.008\"; ", "1r1r2k1/p1p1p3/4n1p1/5p2/8/R3B3/Pn2BPPP/4K2R b K - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.009\"; ", "1r1r2k1/pb3ppp/1p1ppn2/8/PPPP1P2/2NB2P1/3K3P/RR6 w - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.010\"; ", "1r1r3k/p4pp1/3nb2p/2p1q3/8/P1PBPP2/2Q3PP/R1B2RK1 b - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.011\"; ", "1r2r1k1/2qp1ppp/2p1pn2/8/8/2PBQ1P1/PP3P1P/R4RK1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.012\"; ", "1r2r1k1/2qp1ppp/2p2n2/4p3/1P6/2PBQ1P1/P4P1P/R4RK1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.013\"; ", "1r2rn2/1p3pk1/p4npp/P2p4/1P1N2P1/1P3P1P/4BK2/2R1R3 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.014\"; ", "1r3rk1/2qnbppp/2p1p3/pbPpP3/8/PP2QNP1/3B1PBP/2R1R1K1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.015\"; ", "1r4k1/p3pr1p/1qbp1pp1/2p5/2P5/1PN1Q2P/P2R1PP1/3R3K b - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.016\"; ", "1rbr2k1/p1q2p1p/2n1p1p1/1p4Q1/2pPP3/2P3P1/P1B1N1PP/2R2RK1 b - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.017\"; ", "1rq2r2/Q3pp1k/1B1p2pb/4n2p/2PN4/PP5P/3nBPP1/R2R2K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.018\"; ", "1rr3k1/p2qbpnp/Ppp3p1/3pP3/3P4/1Q1B1P2/1P1B1P1P/2R3RK b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.019\"; ", "1rrqb3/1p3kp1/p3p2p/P1Rp1p1P/3P1P2/6P1/1P1QBPK1/2R5 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.020\"; ", "2r1n1k1/1p1R1r1p/2q1pp1B/p5p1/6P1/Q1P4P/PP6/1K1R4 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.021\"; ", "2r1r1k1/1b1n1pp1/1q2p2p/3p3n/P2N4/BP1NPP1P/2B3P1/2R1Q1K1 w - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.022\"; ", "2r1r1k1/1b1q1pp1/4p2p/1Nnp3n/1N6/PP2PP1P/1BB2QP1/3R2K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.023\"; ", "2r1r1k1/1p1npp1p/p2pb1p1/q7/2PnP3/1PNN2PP/P2Q1PB1/2RR2K1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.024\"; ", "2r2bk1/R4pp1/3pqnnp/R3p3/1P2P3/3Q1NNP/2rB1PPK/8 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.025\"; ", "2r2r1k/1bqnbppp/p3p3/1p1pP3/3B1P2/P1NB4/1PP2QPP/R4R1K w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.026\"; ", "2r2rk1/1p2bpp1/p3p3/4P1N1/PqB3P1/1Pn2NQ1/2b2P1P/R3R1K1 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.027\"; ", "2r2rk1/pp3ppp/2nb1q2/P3pb2/2P5/1NB3P1/1Q2PPBP/R4RK1 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.028\"; ", "2r3k1/1pq1b1p1/p1b1pr1p/8/PP2pP2/2P1B3/4B1PP/RQR4K w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.029\"; ", "2r3k1/5p2/pr3p1p/8/3N2q1/P3P1P1/1P1Q1PP1/5RK1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.030\"; ", "2r5/1r2nkp1/p3p2p/1p1b1p1P/8/PP3P2/1KPRB1P1/R5B1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.031\"; ", "2r5/3npk1p/1p1p1r2/pP1P2p1/3N1pP1/1P3P2/2P1R2P/R5K1 w - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.032\"; ", "2rqr1k1/5ppp/n4b2/pbP5/3p4/P4NP1/1N2PPBP/2RQR1K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.033\"; ", "2rr2k1/1b3ppp/pp2pn2/2n5/2BNP3/4KPNP/PP4P1/2R4R w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.034\"; ", "2rr2k1/1q3pp1/pp1pp2p/4n3/2PNP3/1P4P1/P1R1QPKP/3R4 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.035\"; ", "3b2rk/5pp1/2q2n1p/1p2BP2/7P/2NQ4/1PP5/1K4R1 b - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.036\"; ", "3q2k1/1p1bprbp/3pn1p1/3N4/1PP5/r3B3/3QBPPP/2R1R1K1 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.037\"; ", "3r1nk1/pp2q2p/2p3p1/2NnPp2/5P2/1Q6/PP1rNRPP/2R3K1 b - - bm b6; id \"STS(v9.0) Advancement of a/b/c pawns.038\"; ", "3r1rk1/2pq2pp/p4pb1/1p6/4P1P1/2PnQN1P/PP1N1P2/RR4K1 b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.039\"; ", "3r1rk1/3n1pbp/1p1p2p1/pN1Ppn1q/2P3b1/PPN3P1/1B1Q1P1P/R3R1KB w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.040\"; ", "3r2k1/1p2bpp1/pNrppnqp/8/1PPBP3/P4Q1P/5PP1/3RR1K1 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.041\"; ", "3r2k1/5p2/p1prb2p/1p2q3/4Pp2/1P1B1P2/P3Q1PP/2RR1K2 b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.042\"; ", "3rn1k1/1pqn1pp1/p3br1p/2P1p3/P3P3/3BBN1P/2P3PQ/RR5K w - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.043\"; ", "3rr1k1/1bqn1ppp/p1p5/1p2b3/4P3/P3BB1P/1PQ1NPP1/1R1R3K b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.044\"; ", "3rr1k1/1p5p/p2B1bp1/5b2/1RP2P2/1PN5/1P1R1K1P/8 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.045\"; ", "3rr1k1/1q2bp1p/2b3pB/3npP2/1p6/5B2/NPP3PP/3RQR1K w - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.046\"; ", "4b3/ppr1bpk1/2n1p1p1/1B1rP2p/3P3P/P1R1BNP1/5PK1/2R5 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.047\"; ", "4q1k1/p5p1/1rp1p1p1/2R1Pp2/1PQ5/P5P1/5PK1/8 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.048\"; ", "4r1k1/3bpr1p/1qpp1ppQ/p7/2P1N3/1P5P/P2R1PP1/3R3K b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.049\"; ", "4r1k1/p2bpr1p/1qpp2pQ/5p2/2P4P/1P4N1/P2R1PP1/3R3K b - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.050\"; ", "4rk2/2p1rpp1/pbn3bp/1p2P3/PP6/1BP2NNP/5PP1/2R1R1K1 w - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.051\"; ", "4rrk1/1q4pp/4p3/2bp4/5P2/3Q4/1PP3PP/R1B2R1K w - - bm c3; id \"STS(v9.0) Advancement of a/b/c pawns.052\"; ", "4rrk1/p2n2pp/qp2pb2/2p5/2P2P2/P1BP1Q2/4N1PP/1R3RK1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.053\"; ", "5nk1/1bq2pp1/rp1r1b1p/1R1p1B2/2pP4/2N1PN2/PQ3PPP/1R4K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.054\"; ", "5r1k/1p2q1pp/p1p2n2/5r2/3Pp3/4P2R/PPB2PQP/6RK b - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.055\"; ", "5r2/5r1k/p2pN1p1/1p1Pn2p/2q1P2b/P4pR1/1PPQ1B1P/1K2R3 w - - bm b3; id \"STS(v9.0) Advancement of a/b/c pawns.056\"; ", "5rk1/1prn1qp1/p2p3p/3Ppp1P/7R/1NPQ1PP1/PP6/1K1R4 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.057\"; ", "5rk1/2nq2pp/3p1p2/3P4/3B1Q2/PrN3P1/4PP1P/R5K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.058\"; ", "5rk1/p2qp2p/1p1p1pp1/2nN1P1r/P1P1P3/1P2R1P1/1Q4KP/4R3 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.059\"; ", "6k1/1b2bp1p/p3p3/1p2P1p1/2r5/2N1BP2/PP4PP/3R2K1 b - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.060\"; ", "6k1/1p1n1rbp/r2n1pp1/4p3/4P3/4B1P1/PP2N1BP/R4RK1 w - - bm b3; id \"STS(v9.0) Advancement of a/b/c pawns.061\"; ", "6k1/1pr2rp1/p4q1p/2p1p3/2Q1P3/P6P/2P2PP1/3R1RK1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.062\"; ", "6k1/2rqbrpp/2n2n2/pBpppN2/Pp4P1/2PP3P/1P2QP2/R1B1R1K1 w - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.063\"; ", "6k1/4brpp/3p4/p1q1p3/1pN1Pr2/1P1R1P2/P1P3QP/1K4R1 b - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.064\"; ", "6k1/5r2/p4pp1/Br1pp3/2b5/6NP/1P3RP1/2R4K w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.065\"; ", "8/5p2/bk2p3/1pr1Pp2/3p4/bP3BPP/P1nBN3/1R1K4 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.066\"; ", "8/r2b2pk/2p1pr1p/3nQp2/p7/qP3N2/P1PRBPPP/4R1K1 w - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.067\"; ", "b2qr2k/2p3pp/8/1p3p2/2p2B2/2Pp1PPP/5QB1/R6K b - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.068\"; ", "r1b2k2/ppq2p1p/1np3p1/4p3/2n5/3N2P1/P1Q1PPBP/R2R2K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.069\"; ", "r1bq1r2/1pp3bk/3p1npp/1N1Ppn2/PBP1N3/1Q1B4/5PPP/R4RK1 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.070\"; ", "r1r3k1/3nqpp1/1pp1pn1p/p2pN3/2PP1Q2/1P4P1/P2BPPKP/2RR4 b - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.071\"; ", "r1r3k1/p3pp1p/3p2pb/R1nP4/4PP2/2Pp4/1P1N2PP/2BR2K1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.072\"; ", "r1r4k/1q1nbpp1/2bp1n1p/pp2pP2/4P3/P1N2BQ1/1PPN1BPP/2R1R1K1 b - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.073\"; ", "r2q1nk1/1p2rppp/p1p5/3p3b/PP1P4/2NBP3/2Q2PPP/2R2RK1 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.074\"; ", "r2rn1k1/3nqppp/1pp1p3/3p4/pPPP4/P2QN1P1/1B2PP1P/2RR2K1 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.075\"; ", "r3kr2/pp1b1pp1/2p1p2p/4q3/7Q/2PBPR2/PP4PP/2KR4 b q - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.076\"; ", "r3r1k1/1p3pp1/1qp1b2p/p1Rn4/3p4/P2P1BP1/1P1BPP1P/2Q1R1K1 b - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.077\"; ", "r3r1k1/1pb1qpp1/2p1b2p/p3P3/4Q3/2B1PN1P/PP3PP1/3RR1K1 w - - bm a3; id \"STS(v9.0) Advancement of a/b/c pawns.078\"; ", "r3r1k1/pn1qnppp/1p2p3/3pP3/b1pP4/B1P2N2/R1PQBPPP/R5K1 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.079\"; ", "r3rbk1/1npq1pp1/p2p3p/1p6/1P1P4/P1R1BN1P/5PP1/3QR1K1 b - - bm c6; id \"STS(v9.0) Advancement of a/b/c pawns.080\"; ", "r3rbk1/1qpn1pp1/p4n1p/1p2pN2/2P1P3/5N2/PPQB1PPP/R3R1K1 b - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.081\"; ", "r3rn1k/1q2b1p1/pp1p1n1p/4pQ2/P3P3/1NN1BR2/1PP3PP/5R1K b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.082\"; ", "r4rk1/1p4bp/2qp1np1/p1n1p3/2P5/P1B1N3/1PB2PPP/R2Q1RK1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.083\"; ", "r4rk1/2Q2ppp/4p3/p3P3/q1P5/P5P1/5P1P/2R1R1K1 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.084\"; ", "r4rk1/2qb1ppp/p2pp3/1pn3P1/3RPP2/P1N2Q2/1PP3BP/2KR4 b - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.085\"; ", "r4rk1/4bppp/b3pn2/1p1q2B1/3p4/3B1N2/PP2QPPP/R2R2K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.086\"; ", "r4rkb/p2bp2p/2nq2pP/1p6/2pP4/2P1B1N1/P1B2PP1/2RQR1K1 w - - bm a4; id \"STS(v9.0) Advancement of a/b/c pawns.087\"; ", "r5k1/1pp1r1pp/3pbpq1/pB2n3/P1P5/1P2BP2/2PQ2PP/2KRR3 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.088\"; ", "r5k1/1rpn1pbp/p2pp3/1p4Np/2PP4/1PN1P1P1/P4PK1/2RR4 w - - bm c5; id \"STS(v9.0) Advancement of a/b/c pawns.089\"; ", "r5k1/2p1qp2/1p1p2bp/p1nPr1p1/2P5/PP2P1N1/1Q1B2PP/3R1RK1 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.090\"; ", "r5k1/5q1p/2ppNr1b/2pPp1pP/p1P3P1/P7/1PQ1RPK1/1R6 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.091\"; ", "rr2q1k1/3bnpb1/ppp3pp/3p4/1P1P4/PQ1BP1NP/1NR2PP1/3R2K1 b - - bm a5; id \"STS(v9.0) Advancement of a/b/c pawns.092\"; ", "1r1rb1k1/pp3pbp/4p1p1/1P2P3/2PBQ3/q7/P3B1PP/2R2R1K b - - bm a6; id \"STS(v9.0) Advancement of a/b/c pawns.093\"; ", "2r1k2r/1n2ppb1/p2p2p1/1p1P3p/8/1P2BP1P/P1P1BP2/2KR2R1 w k - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.094\"; ", "2r2rk1/1pqn3p/p2p1npb/N2Pp3/2P2p2/Q4PP1/PP2BBKP/3RR3 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.095\"; ", "2r3k1/p1q1bpp1/2p2n2/2Np3r/1P1B3p/P1Q4P/5PP1/2R1R1K1 w - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.096\"; ", "3r2k1/4rppp/2ppbn2/Nq2p3/4P3/1P2Q1PP/P1PR1PBK/4R3 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.097\"; ", "r6k/p3Npb1/qp4pp/4p3/1B6/1PP3P1/P2R1P1P/3R2K1 b - - bm b5; id \"STS(v9.0) Advancement of a/b/c pawns.098\"; ", "r6r/4p1k1/3q1p2/p1pPn1p1/1p2P2p/4Q3/PP2BPPP/1R2R1K1 b - - bm c4; id \"STS(v9.0) Advancement of a/b/c pawns.099\"; ", "rq4kb/5p1p/3p1Pp1/p2Pp1P1/3pP1bP/1P6/P1Q2R2/4BBK1 w - - bm b4; id \"STS(v9.0) Advancement of a/b/c pawns.100\"; ", "1b1qrr2/1p4pk/1np4p/p3Np1B/Pn1P4/R1N3B1/1Pb2PPP/2Q1R1K1 b - - bm Bxe5; id \"STS(v10.0) Simplification.001\"; c0 \"Bxe5=10, f4=3, Nc4=2\";", "1k1r2r1/1b4p1/p4n1p/1pq1pPn1/2p1P3/P1N2N2/1PB1Q1PP/3R1R1K b - - bm Nxf3; id \"STS(v10.0) Simplification.002\"; c0 \"Nxf3=10, Rge8=7, Rgf8=6, Rh8=7\";", "1k1r3r/pb1q2p1/B4p2/2p4p/Pp1bPPn1/7P/1P2Q1P1/R1BN1R1K b - - bm Bxa6; id \"STS(v10.0) Simplification.003\"; c0 \"Bxa6=10, Qc6=3, Qe6=3, Rde8=5\";", "1k1r4/1br2p2/3p1p2/pp2pPb1/2q1P2p/P1PQNB1P/1P4P1/1K1RR3 b - - bm Qxd3+; id \"STS(v10.0) Simplification.004\"; c0 \"Qxd3+=10, Qa4=6, Qb3=5, Qc5=6\";", "1k1r4/1br2p2/3p1p2/pp2pPb1/4P2p/P1PRNB1P/1P4P1/1K2R3 b - - bm Bxe3; id \"STS(v10.0) Simplification.005\"; c0 \"Bxe3=10, b4=7, Ka7=6, Rc5=6\";", "1k1r4/5qp1/p1b2n1p/1p2p3/2p1P2P/P1N1P1P1/1PB1Q3/3R2K1 b - - bm Rxd1+; id \"STS(v10.0) Simplification.006\"; c0 \"Rxd1+=10, Qc7=4, Qe7=4, Qf8=4\";", "1k1rr3/p1p4p/Bpnb4/3p1qp1/N2P4/P2Q1PPb/1PP3NP/2KR2R1 w - - bm Qxf5; id \"STS(v10.0) Simplification.007\"; c0 \"Qxf5=10, Bb5=3, Nc3=5, Qd2=1\";", "1kr5/3n2p1/q2rpn1p/p7/Ppp2P2/5BP1/1PQ2B1P/2RR2K1 w - - bm Rxd6; id \"STS(v10.0) Simplification.008\"; c0 \"Rxd6=10, Kh1=4, Qe2=7, Rd4=4\";", "1nr2qk1/pb1r1p1p/1b4pP/1p1Bp1B1/4P1Q1/2NR4/P1R2PP1/6K1 w - - bm Bxb7; id \"STS(v10.0) Simplification.009\"; c0 \"Bxb7=10, Rdd2=1\";", "1qr3k1/p3bppp/4pn2/1B2n3/N7/P3P2P/1P2QPP1/2R1B2K w - - bm Rxc8+; id \"STS(v10.0) Simplification.010\"; c0 \"Rxc8+=10, Nc3=6, Rc3=6, Rd1=6\";", "1r1q1n2/2p2ppk/p2p3p/P1b1p3/2P1P3/3P1N1P/1R1B1PP1/1Q4K1 b - - bm Rxb2; id \"STS(v10.0) Simplification.011\"; c0 \"Rxb2=10, Nd7=3, Ra8=2, Rc8=2\";", "1r1qr1k1/2Q1bp1p/2n3p1/2PN4/4B3/2N3P1/5P1P/5RK1 b - - bm Qxc7; id \"STS(v10.0) Simplification.012\"; c0 \"Qxc7=10, Nb4=2, Rc8=1\";", "1r1r2k1/6pp/1b2p2q/3b1p2/1BB1n3/P3PN1P/2Q2PP1/2R2RK1 w - - bm Bxd5; id \"STS(v10.0) Simplification.013\"; c0 \"Bxd5=10, Nd4=3, Qb3=3, Rfe1=2\";", "1r1r3k/1qpn1pbp/p1n3pB/P2bp3/BpN3Q1/3P3P/1PPN1PP1/R3R1K1 w - - bm Bxg7+; id \"STS(v10.0) Simplification.014\"; c0 \"Bxg7+=10, Qg5=1, Qh4=4\";", "1r2k2r/pp1npp2/2n3p1/7p/3bP3/P3BB1P/1P3PP1/1R1R1NK1 b k - bm Bxe3; id \"STS(v10.0) Simplification.015\"; c0 \"Bxe3=10, Bb6=6, Bc5=6, e5=6\";", "1r3r2/3q2kp/p2p1pp1/2pPp3/4Pn2/P2P1N1P/2Q2PP1/1R2R1K1 w - - bm Rxb8; id \"STS(v10.0) Simplification.016\"; c0 \"Rxb8=10, Kh1=5, Kh2=5, Nd2=5\";", "1r3rk1/pp3pp1/1np4p/2Nn2bq/3P3N/P2Q2PP/1P1BRP2/4R1K1 w - - bm Bxg5; id \"STS(v10.0) Simplification.017\"; c0 \"Bxg5=10, Qf3=2, Re4=2, Re5=2\";", "1r4k1/1q2r2p/1n4pQ/2pp1pN1/7P/P5P1/1P3P2/3RR1K1 w - - bm Rxe7; id \"STS(v10.0) Simplification.018\"; c0 \"Rxe7=10, h5=4, Nf3=4, Nxh7=3\";", "1r4k1/5ppp/1p3n2/5n2/NP1r4/1B3P2/1P4PP/3RR2K w - - bm Rxd4; id \"STS(v10.0) Simplification.019\"; c0 \"Rxd4=10, b5=1, Bc2=2, Nc3=2\";", "1r4k1/p1rn1ppp/2p1p1b1/N1PpP3/3P1P2/1R4P1/P6P/R4BK1 w - - bm Rxb8+; id \"STS(v10.0) Simplification.020\"; c0 \"Rxb8+=10, Ba6=3, Rc1=3, Re1=3\";", "1r4r1/4kp1p/3p1p1b/2q1pP2/Bn2P3/2N5/1PPNQ1PP/1K1R4 b - - bm Bxd2; id \"STS(v10.0) Simplification.021\"; c0 \"Bxd2=10, Rgd8=1\";", "1r4rk/2q1b2p/pN6/P1p1Pp2/3n1p2/5N2/5QPP/R4RK1 b - - bm Nxf3+; id \"STS(v10.0) Simplification.022\"; c0 \"Nxf3+=10, Qb7=5, Rbd8=7, Rgd8=5\";", "1r6/1R2bk2/P3p1pp/4Pp2/1r1P3P/1N2B1P1/5PK1/8 w - - bm Rxb4; id \"STS(v10.0) Simplification.023\"; c0 \"Rxb4=10, Rxb8=6\";", "1r6/3n4/p2b3p/2nN1kpP/1BP1p3/3rP3/3NKP2/1R1R4 w - - bm Bxc5; id \"STS(v10.0) Simplification.024\"; c0 \"Bxc5=10, Bc3=3, Nxe4=2, Rf1=2\";", "1r6/8/p2b3p/2nN1kpP/2P1p3/3rP3/3NKP2/1R1R4 w - - bm Rxb8; id \"STS(v10.0) Simplification.025\"; c0 \"Rxb8=10, Ne7+=6\";", "1rb2nk1/8/1p1PNbrp/3Pp1pq/p3Pn1P/P2N1PB1/4B3/R2Q1R1K w - - bm Nxf8; id \"STS(v10.0) Simplification.026\"; c0 \"Nxf8=10, Nc7=4, Rc1=1\";", "2br1rk1/2q3p1/1pp1p2p/p1n1b3/2BNN1Q1/4P3/PP3PP1/2RR3K w - - bm Nxc5; id \"STS(v10.0) Simplification.027\"; c0 \"Nxc5=10, Kg1=2, Nf3=2, Nxe6=3\";", "2br2k1/r5p1/4p3/5p2/8/pP3B2/1q2RPPP/Q3R1K1 b - - bm Qxa1; id \"STS(v10.0) Simplification.028\"; c0 \"Qxa1=10, Qd4=1, Qxb3=1, Rd2=3\";", "2brr1k1/2q1bpp1/pNnpp2p/P1p5/1P2PP2/2P1B1P1/4Q1BP/R2R2K1 w - - bm Nxc8; id \"STS(v10.0) Simplification.029\"; c0 \"Nxc8=10, b5=3, bxc5=4, Rab1=3\";", "2r1n1k1/5ppp/1prp4/p3p1q1/2b1P3/P1B1QB1P/1PPR1PPK/R7 b - - bm Qxe3; id \"STS(v10.0) Simplification.030\"; c0 \"Qxe3=10, h6=2, Qe7=2, Qh4=2\";", "2r1r1k1/1p1q1bbp/pn3pp1/n2p4/3P1B1P/2NB1N2/PPQ1RPP1/4R1K1 w - - bm Rxe8+; id \"STS(v10.0) Simplification.031\"; c0 \"Rxe8+=10, h5=8, Qb1=5\";", "2r1r1k1/2qbppbp/pp1p2p1/n2P4/P1P4P/1P3N2/1BQ1BPP1/R2R2K1 w - - bm Bxg7; id \"STS(v10.0) Simplification.032\"; c0 \"Bxg7=10, Bd4=3, h5=3, Ng5=2\";", "2r2nk1/pp3p2/5qpb/4p1Np/P3P2P/1P2B1P1/2r2P2/2RRQ1K1 w - - bm Rxc2; id \"STS(v10.0) Simplification.033\"; c0 \"Rxc2=10, Kg2=2\";", "2r2r1k/1p1q2b1/pQn1b1pp/4pp2/B3P3/1P3N1P/P1RB1PP1/R5K1 w - - bm Bxc6; id \"STS(v10.0) Simplification.034\"; c0 \"Bxc6=10, Bb4=4, Be3=2, Rac1=1\";", "2r3k1/4qpp1/4p2p/1P1bP3/4pPP1/4Q3/4B2P/2R3K1 b - - bm Rxc1+; id \"STS(v10.0) Simplification.035\"; c0 \"Rxc1+=10\";", "2r3k1/pp3pp1/4q2p/4p3/bB2Pn2/P4P2/1P1Q2PP/2R2BK1 w - - bm Rxc8+; id \"STS(v10.0) Simplification.036\"; c0 \"Rxc8+=10, Bc5=4, Qe3=2, Rc3=4\";", "2r5/4q1kp/1nB2pp1/p3p3/Pb2Q3/4P3/1B1r1PPP/1R1R2K1 b - - bm Rxd1+; id \"STS(v10.0) Simplification.037\"; c0 \"Rxd1+=10, Rcd8=2\";", "2rk1br1/4np1p/p2pb3/1p1Npp2/P3P3/2PB2Pq/1PN2P1P/R2Q1R1K w - - bm Nxe7; id \"STS(v10.0) Simplification.038\"; c0 \"Nxe7=10, Nb6=4, Ncb4=6, Ndb4=3\";", "2rnq2k/pb3pp1/1p5p/3B4/1P3Q2/P4N1P/2R2PP1/6K1 w - - bm Rxc8; id \"STS(v10.0) Simplification.039\"; c0 \"Rxc8=10, Bb3=3, Rc4=5, Rd2=1\";", "2rq1r1k/3n2pp/1p2p3/1P1b2bn/p1BP4/P4NP1/1B1NQP2/2R1R1K1 w - - bm Bxd5; id \"STS(v10.0) Simplification.040\"; c0 \"Bxd5=10, Bd3=1, Nxg5=2, Rc3=2\";", "2rq1rk1/1p2bpp1/4p3/pP1pP1np/P2P4/R3BP2/3Q2PP/1NR3K1 w - - bm Rxc8; id \"STS(v10.0) Simplification.041\"; c0 \"Rxc8=10, Ra2=1, Rac3=3, Rb3=1\";", "2rr1bk1/3qnppp/pp6/3p4/2PP2Q1/PP5P/1B1N2P1/2R2R1K b - - bm Qxg4; id \"STS(v10.0) Simplification.042\"; c0 \"Qxg4=10, dxc4=2, f6=1, g6=2\";", "2rr2k1/p4pp1/1p2pn1p/3b1P2/1qNP4/1P1B4/P2Q2PP/2RR2K1 b - - bm Qxd2; id \"STS(v10.0) Simplification.043\"; c0 \"Qxd2=10, a5=3, Qe7=2, Qf8=2\";", "3b4/2q2pkp/p2p1np1/1b1Pp1B1/1pN1P3/1P5P/P1Q2PP1/5NK1 b - - bm Bxc4; id \"STS(v10.0) Simplification.044\"; c0 \"Bxc4=10, a5=1, Be7=1, h6=2\";", "3n1r2/2r4p/p2bp2k/1p1p2pP/1P1P4/P1R1B1Pq/4QP2/1B2R1K1 w - - bm Rxc7; id \"STS(v10.0) Simplification.045\"; c0 \"Rxc7=10, Rec1=2\";", "3q4/pp2b1k1/2r5/4p2p/P1RpN3/1P3PP1/1Q2P1K1/8 w - - bm Rxc6; id \"STS(v10.0) Simplification.046\"; c0 \"Rxc6=10, Nd2=3, Qb1=2, Qc2=4\";", "3r1k2/p4ppp/1r2p3/n1p1P3/5P1P/P1PBK1P1/8/1R3R2 w - - bm Rxb6; id \"STS(v10.0) Simplification.047\"; c0 \"Rxb6=10, a4=5, h5=8, Rfd1=4\";", "3r1q1k/Q2R1bpp/3b1r2/2p2p2/2N2P2/1Pp3P1/5PBP/4R1K1 w - - bm Rxd8; id \"STS(v10.0) Simplification.048\"; c0 \"Rxd8=10, h4=5, Nxd6=5, Rc1=6\";", "3r1rk1/4b1p1/p3p3/4pbPp/2R4P/1PN5/PB3P2/3R2K1 w - - bm Rxd8; id \"STS(v10.0) Simplification.049\"; c0 \"Rxd8=10, Rc7=2\";", "3r2k1/1b1rnp1p/p2qpbp1/1pR5/1P1PB2P/P3BN2/4QPP1/3R2K1 w - - bm Bxb7; id \"STS(v10.0) Simplification.050\"; c0 \"Bxb7=10, Bg5=7\";", "3r4/5pk1/4rqp1/p2p4/Pb1Q3p/1Pp1P2P/2R1BPP1/3R2K1 b - - bm Qxd4; id \"STS(v10.0) Simplification.051\"; c0 \"Qxd4=10, g5=6, Re4=5, Red6=5\";", "3rkb2/1p4rp/p4p2/2p2B2/2N1Pp2/3R2P1/PPP2P1P/6K1 b - - bm Rxd3; id \"STS(v10.0) Simplification.052\"; c0 \"Rxd3=10, Be7=2, fxg3=2, Rd4=3\";", "3rr1k1/6p1/pb1p3p/1p1RnBqP/4PQN1/2P5/PP6/1K3R2 w - - bm Qxg5; id \"STS(v10.0) Simplification.053\"; c0 \"Qxg5=10, a3=3, Kc2=3, Nxe5=4\";", "4qbk1/r1p1nbpp/1p3p2/1Q6/P2P4/2BN1BP1/5P1P/2R3K1 w - - bm Qxe8; id \"STS(v10.0) Simplification.054\"; c0 \"Qxe8=10, Bb2=5, h3=5, Nf4=5, Nf4=6\";", "4r1k1/1p2qp1p/2p1n1pB/p3p3/P3P1B1/2N2Q1P/2P2PP1/6K1 w - - bm Bxe6; id \"STS(v10.0) Simplification.055\"; c0 \"Bxe6=10, Qd1=2, Qd3=1, Qe3=2\";", "4r1k1/1p5p/1r4p1/2pq1p2/P4P2/3P2Q1/1bP3RP/4R1BK b - - bm Rxe1; id \"STS(v10.0) Simplification.056\"; c0 \"Rxe1=10, Ra8=2, Rbe6=3, Rc8=3\";", "4r1k1/2r1bp2/1p4p1/3BP2p/nP5P/5K2/1B1R1P2/2R5 b - - bm Rxc1; id \"STS(v10.0) Simplification.057\"; c0 \"Rxc1=10, Ra7=1, Rcc8=3\";", "4r1k1/2r2ppp/2nq1n2/1BbppP2/Q7/2P1BN1P/5PP1/RR4K1 w - - bm Bxc5; id \"STS(v10.0) Simplification.058\"; c0 \"Bxc5=10, Nd2=6, Qb3=6, Re1=6\";", "4r2k/p1r1b1pp/1p1pqn2/4p3/1PP4B/P4B1P/4QPP1/2RR2K1 w - - bm Bxf6; id \"STS(v10.0) Simplification.059\"; c0 \"Bxf6=10, Qd2=6, Qe3=6, Re1=6\";", "4r2k/p2n1pp1/4p2p/1q1r3P/2pR1BP1/P1P1R3/1P2QP2/2K5 b - - bm Rxd4; id \"STS(v10.0) Simplification.060\"; c0 \"Rxd4=10, Nc5=4, Rc8=2\";", "4r3/1pn3k1/4p1b1/p1Pp3r/3P2NR/1P3B2/3K2P1/4R3 w - - bm Rxh5; id \"STS(v10.0) Simplification.061\"; c0 \"Rxh5=10, g3=3, Reh1=3\";", "4rrk1/2pb3p/p7/1ppPq3/2P1P1pP/2N5/PP2Q2P/4RR1K w - - bm Rxf8+; id \"STS(v10.0) Simplification.062\"; c0 \"Rxf8+=10, a3=3, Kg2=4, Rf2=2\";", "5B1k/p6p/1p2q1r1/2p1P1p1/3b1n2/PQ3R2/1P4P1/K2R4 w - - bm Qxe6; id \"STS(v10.0) Simplification.063\"; c0 \"Qxe6=10, g3=3, Qc2=1\";", "5k2/4pp2/1N2n1pp/r3P3/P5PP/2rR1K2/P7/3R4 b - - bm Rxd3+; id \"STS(v10.0) Simplification.064\"; c0 \"Rxd3+=10, Rc6=4\";", "5qk1/1p1rbrpp/pP3p2/P1pbp3/1n6/BN1P2P1/1Q2PPBP/R1R3K1 w - - bm Bxd5; id \"STS(v10.0) Simplification.065\"; c0 \"Bxd5=10, Bxb4=7, Rab1=6, Rc3=4\";", "5rk1/8/3p3p/p1qP2p1/Rrb1P3/3p1P2/1P1Q1RP1/3N2K1 w - - bm Rxb4; id \"STS(v10.0) Simplification.066\"; c0 \"Rxb4=10, b3=3, Ra3=2\";", "6k1/1r3pp1/4b2p/p2pP2P/1r1R1Q2/1Pq1N3/2P3P1/3R3K b - - bm Rxd4; id \"STS(v10.0) Simplification.067\"; c0 \"Rxd4=10, R7b5=5, R7b6=4, Rb8=5\";", "6k1/3q2b1/p1rrnpp1/P3p3/4P3/1pBR3Q/1P4PP/1B1R3K b - - bm Rxd3; id \"STS(v10.0) Simplification.068\"; c0 \"Rxd3=10, Bf8=6, Nd4=5, Qc7=5\";", "6k1/3qbppp/5n2/PQpPp3/4P3/5PP1/1P4KP/2B5 w - - bm Qxd7; id \"STS(v10.0) Simplification.069\"; c0 \"Qxd7=10\";", "6k1/5p2/1q1bp1p1/1Pp1B2p/2Pn3P/6P1/1Q2BP2/6K1 w - - bm Bxd6; id \"STS(v10.0) Simplification.070\"; c0 \"Bxd6=10, Bf6=2, Bxd4=1, f4=2\";", "6r1/4pp1k/3p3p/2qP1Pb1/r3P1PB/1R5K/4Q3/1R6 b - - bm Bxh4; id \"STS(v10.0) Simplification.071\"; c0 \"Bxh4=10, h5=5, Qd4=5, Rc8=2\";", "7r/2r1kp2/3pp2p/p3q1p1/4B3/P5P1/1Q1B1P1P/4R1K1 w - - bm Qxe5; id \"STS(v10.0) Simplification.072\"; c0 \"Qxe5=10, Qb1=5, Qb3=3, Qb6=3\";", "8/1p1bkq2/p2pp1n1/P1b1p1P1/4P1QN/1KNB4/1PP5/8 b - - bm Nxh4; id \"STS(v10.0) Simplification.073\"; c0 \"Nxh4=10, Bc6=5, Be8=4, Bf2=5\";", "8/3n1nk1/q2b4/3p2p1/2pPp3/2P1P3/1Q4PN/3BB1K1 b - - bm Bxh2+; id \"STS(v10.0) Simplification.074\"; c0 \"Bxh2+=10, Bc7=4, Nf6=4, Nh6=4\";", "8/p1r4p/1p1qnkpP/3Ppp2/8/P2Q2P1/BP3P2/2R3K1 w - - bm Rxc7; id \"STS(v10.0) Simplification.075\"; c0 \"Rxc7=10, Rc3=6, Rc4=6, Re1=6\";", "8/r4p2/P1ppk3/2p4p/1rPb1BqP/RR1PpQP1/4P1K1/8 b - - bm Qxf3+; id \"STS(v10.0) Simplification.076\"; c0 \"Qxf3+=10, f5=2, Ra8=1, Rxb3=1\";", "br2r1k1/5p1p/p7/nq4Pp/p3P3/P1PQ4/1P2R1B1/K1BR4 b - - bm Qxd3; id \"STS(v10.0) Simplification.077\"; c0 \"Qxd3=10, Nb3+=5, Rbc8=4, Rbd8=4\";", "br3rk1/p2q1pp1/3p1n1p/2p1p3/2PnP3/P1BP1NP1/1R1Q1PBP/1R4K1 b - - bm Rxb2; id \"STS(v10.0) Simplification.078\"; c0 \"Rxb2=10, Nxf3+=4, Qc7=4, Rb7=5\";", "q3b3/4Bpkp/6p1/3Pp3/r3r3/1Q5P/R4PP1/R5K1 w - - bm Rxa4; id \"STS(v10.0) Simplification.079\"; c0 \"Rxa4=10, Bd6=4, Kh1=5, Ra3=5\";", "qr3nk1/r4p1p/2p1p1pP/p1PpPbP1/3P1P2/QR2R3/P2NB2K/8 w - - bm Rxb8; id \"STS(v10.0) Simplification.080\"; c0 \"Rxb8=10, Kg3=2, Qb2=4, Rb6=3\";", "qr4k1/3b1pp1/4p2p/n2pP3/n1pP4/Q1P2NP1/3N1P1P/1R3BK1 b - - bm Rxb1; id \"STS(v10.0) Simplification.081\"; c0 \"Rxb1=10, Bc6=2, Be8=3, Rb7=2\";", "R1b2b2/2kp1p1p/B2npp2/2p5/4P1r1/6P1/3N1P1P/3K3R w - - bm Bxc8; id \"STS(v10.0) Simplification.082\"; c0 \"Bxc8=10, f3=3, h3=3, Kc2=3\";", "r1b2rk1/1p2bpp1/5n2/1Q2pq2/2P1N3/p3B1Pp/P2RPP1P/3R2KB w - - bm Nxf6+; id \"STS(v10.0) Simplification.083\"; c0 \"Nxf6+=10, Nc3=4, Ng5=2, Qb1=1\";", "r1bq4/3n1pkp/2pRr1p1/8/nPP1PP2/6PP/2Q1N1B1/1R4K1 w - - bm Rxe6; id \"STS(v10.0) Simplification.084\"; c0 \"Rxe6=10, Rdd1=3\";", "r1r1bnk1/5pp1/p2pp3/2q1n1P1/3QP2P/1PN4B/2P1NR1K/3R4 b - - bm Qxd4; id \"STS(v10.0) Simplification.085\"; c0 \"Qxd4=10, a5=5, Bb5=4, Rab8=3\";", "r2qr1k1/2p2pp1/3p1n2/3P1n1p/1Q3P2/1B5P/PP4PB/2R1R2K w - - bm Rxe8+; id \"STS(v10.0) Simplification.086\"; c0 \"Rxe8+=10, Qc4=5, Ra1=4, Rb1=4\";", "r2r2k1/1b1nqpp1/pp5p/2pNP3/P3Q3/5N2/1P3PPP/2RR2K1 b - - bm Bxd5; id \"STS(v10.0) Simplification.087\"; c0 \"Bxd5=10, Kh8=6, Qe6=6, Qe8=6\";", "r2r2k1/4qp2/p5p1/2p4p/5P2/3RP1K1/PPQ4P/3R4 b - - bm Rxd3; id \"STS(v10.0) Simplification.088\"; c0 \"Rxd3=10, h4+=2, Rdb8=2, Re8=4\";", "r3r1k1/2qn3p/1p2ppp1/3b4/p1PP1P2/4QN2/R5PP/1R3BK1 b - - bm Bxf3; id \"STS(v10.0) Simplification.089\"; c0 \"Bxf3=10, Bb7=4, Bc6=5, Bxc4=3\";", "r3r1k1/5pbp/4bpp1/pp2q3/4P1PP/P1NR2Q1/1PP1B3/2KR4 b - - bm Qxg3; id \"STS(v10.0) Simplification.090\"; c0 \"Qxg3=10, Qb8=1, Qc5=2\";", "r3r1k1/6p1/p2p1qp1/1p1P3p/4P1bP/P2Q3B/1PP5/1K2R2R b - - bm Bxh3; id \"STS(v10.0) Simplification.091\"; c0 \"Bxh3=10, Bc8=5, Qxh4=5, Rf8=5\";", "r3r3/p5bk/2pq1ppp/1p1b4/3P4/P2N1N2/1P3PPP/2RQR1K1 b - - bm Rxe1+; id \"STS(v10.0) Simplification.092\"; c0 \"Rxe1+=10, a5=6, h5=7, Rac8=5\";", "r3rbk1/p1qn1p1p/2p1n1p1/Pp2p1B1/1P2P3/2N1Q3/2PN1PPP/1R2R1K1 b - - bm Nxg5; id \"STS(v10.0) Simplification.093\"; c0 \"Nxg5=10, a6=3, Nb8=3, Rac8=4\";", "r4r1k/1bq1bppp/p2p4/1p1Nn3/4PR2/PN1B3Q/1PP3PP/R5K1 b - - bm Bxd5; id \"STS(v10.0) Simplification.094\"; c0 \"Bxd5=10, Bc8=5, Qc8=5, Qd8=1\";", "r4rk1/1p2bppp/p3bn2/8/Pq1BP3/1BN1Q3/1PP3PP/R3K2R w KQ - bm Bxe6; id \"STS(v10.0) Simplification.095\"; c0 \"Bxe6=10, e5=2, O-O-O=2, Rd1=1\";", "r4rk1/pp1qppbp/2n3p1/3b4/3PB2B/2P5/3N1PPP/1R1QR1K1 b - - bm Bxe4; id \"STS(v10.0) Simplification.096\"; c0 \"Bxe4=10, e6=5, Rac8=3, Rfe8=4\";", "r4rk1/pp5p/2pp2pb/2n1nq2/2P2P2/2N1B3/PP2B1PP/2RQR1K1 w - - bm Bxc5; id \"STS(v10.0) Simplification.097\"; c0 \"Bxc5=10, g4=6, Kh1=6, Rf1=6\";", "r4rk1/pppb3p/8/2pPqp2/2P1P1nP/1QN4B/PP5P/4RRK1 w - - bm Bxg4; id \"STS(v10.0) Simplification.098\"; c0 \"Bxg4=10, Qc2=3, Rf4=5\";", "r5k1/5p2/7p/5qP1/1P1QR3/5P2/r4RK1/8 b - - bm Rxf2+; id \"STS(v10.0) Simplification.099\"; c0 \"Rxf2+=10, h5=6, hxg5=6, R2a6=6\";", "rr4k1/p2nBpp1/q1p1pn1p/7P/2pPN3/P1P5/1PQ2PP1/2KR3R b - - bm Nxe4; id \"STS(v10.0) Simplification.100\"; c0 \"Nxe4=10, Rb3=4, Rb5=4\";", "1k2r3/1p1bP3/2p2p1Q/Ppb5/4Rp1P/2q2N1P/5PB1/6K1 b - - bm Kc7; id \"STS(v11.0) King Activity.001\"; c0 \"Kc7=10, Kc8=4, Qa1+=4\";", "1k2r3/p7/Pp1pP1p1/4p2p/2r4P/5P1B/4RB1K/8 w - - bm Kg3; id \"STS(v11.0) King Activity.002\"; c0 \"Kg3=10, Kg2=5, Re1=5, Re3=3\";", "1k5r/6p1/p2b4/7p/2r1p2P/R1B1P3/6P1/2R3K1 b - - bm Ka7; id \"STS(v11.0) King Activity.003\"; c0 \"Ka7=10, Bxa3=3, Kb7=4, Rc6=2\";", "1n5k/3r2p1/2p1qp1p/3p1N1P/1P1P1rP1/p1R5/P7/1KRQ4 w - - bm Ka1; id \"STS(v11.0) King Activity.004\"; c0 \"Ka1=10, Re3=2, Rg3=3\";", "1r2r3/1p1b3k/2p2n2/p1Pp4/P2N1PpP/1R2p3/1P2P1BP/3R2K1 b - - bm Kg6; id \"STS(v11.0) King Activity.005\"; c0 \"Kg6=10, Kh6=8, Ne4=8, Nh5=8\";", "1r2rqk1/8/bn1p3p/B1p2p2/p1PnpP2/P3R2Q/1P3NPP/2R2BK1 b - - bm Kh7; id \"STS(v11.0) King Activity.006\"; c0 \"Kh7=10, Re6=3\";", "1R3bk1/7p/6p1/8/1pN3P1/8/r4P1P/6K1 b - - bm Kf7; id \"STS(v11.0) King Activity.007\"; c0 \"Kf7=10, Kg7=1\";", "1r3k2/2N2pp1/1pR2n1p/4p3/8/1P1K1P2/P5PP/8 w - - bm Kc4; id \"STS(v11.0) King Activity.008\"; c0 \"Kc4=10, a4=6, Ke3=2, Nb5=2\";", "1r3k2/3n1p2/6pN/2p1PP2/p2q4/Pr1p2P1/1P1R1R1P/3Q2K1 b - - bm Ke7; id \"STS(v11.0) King Activity.009\"; c0 \"Ke7=10, Ke8=2, Kg7=2\";", "2b4r/1p1k4/1pnbppp1/r2p3p/2pP1P1P/2P2NPB/PPN2P2/R3R1K1 b - - bm Ke7; id \"STS(v11.0) King Activity.010\"; c0 \"Ke7=10, Nd8=3, Re8=2\";", "2k2r1r/1b4p1/1nq1p3/1p5p/5P2/1Pp1B1KP/2B1QRP1/R7 w - - bm Kh2; id \"STS(v11.0) King Activity.011\"; c0 \"Kh2=10, Bd3=7\";", "2k3r1/1b2bp2/2p2n2/pp2p1Bp/2p1P2P/P2n1B2/1P1RN1P1/5K1R b - - bm Kc7; id \"STS(v11.0) King Activity.012\"; c0 \"Kc7=10, a4=3, Ba6=1, c5=2, Kb8=3\";", "2kr1b1r/1bq2pp1/p3pn2/7p/1ppPN2P/4PQ2/PPBB1PP1/R1R3K1 b - - bm Kb8; id \"STS(v11.0) King Activity.013\"; c0 \"Kb8=10, a5=2, Bd5=2, e5=2, Rh6=3\";", "2kr3r/p3p3/1pn2pp1/1R5p/4P2P/2P1BPP1/P3K3/7R b - - bm Kb7; id \"STS(v11.0) King Activity.014\"; c0 \"Kb7=10, Rd6=7, Rd7=7\";", "2q2r2/3bbpkp/r2p4/p1pPp1P1/PpP1P2P/1P3QK1/4RN2/2B3R1 w - - bm Kh2; id \"STS(v11.0) King Activity.015\"; c0 \"Kh2=10, Ng4=6, Qh5=5\";", "2r1b3/p3kpp1/7p/3P4/7P/2p1KPP1/P7/1BR5 w - - bm Kd4; id \"STS(v11.0) King Activity.016\"; c0 \"Kd4=10, Bc2=7, Bf5=7\";", "2r1k2r/1q1bbp2/p4p2/1p2pP1p/8/1N1B2Q1/PPP3PP/1K1RR3 b k - bm Kf8; id \"STS(v11.0) King Activity.017\"; c0 \"Kf8=10, Kd8=6, Rf8=6\";", "2r1r3/1k1b1p2/1p4p1/p3n3/2PRP2p/PP1NK2P/2R3B1/8 b - - bm Kc7; id \"STS(v11.0) King Activity.018\"; c0 \"Kc7=10, Bc6=9, Kc6=9, Rc7=9\";", "2r2bk1/1Q3ppp/p6r/P2BP2q/5Pb1/1P1RR1P1/3B4/6K1 w - - bm Kf1; id \"STS(v11.0) King Activity.019\"; c0 \"Kf1=10, Bc3=8, Bg2=8, Bxf7+=8\";", "2r2k2/4pp2/pp6/2pPn3/4PN1p/1P5P/P4P2/2R2K2 w - - bm Ke2; id \"STS(v11.0) King Activity.020\"; c0 \"Ke2=10, Ng2=3, Rc3=3\";", "2r2k2/p4pp1/b3n2p/8/1pp1P2P/4NPP1/PPB3K1/3R4 w - - bm Kf2; id \"STS(v11.0) King Activity.021\"; c0 \"Kf2=10, Nd5=2, Rd2=1\";", "2r3k1/1q6/4p3/p2p2bp/P2P1n2/2P1NP2/1PB4B/1R2R1K1 b - - bm Kf7; id \"STS(v11.0) King Activity.022\"; c0 \"Kf7=10, Kf8=3, Rf8=6\";", "2r3k1/2r1b3/p3p2p/3n2p1/2N1KP2/P2N2PP/2R5/2R5 b - - bm Kg7; id \"STS(v11.0) King Activity.023\"; c0 \"Kg7=10, Kh7=1\";", "2rb2k1/1p1q3p/1P2b1p1/1N3p2/3B4/4PP1P/1Q4P1/R5K1 w - - bm Kh2; id \"STS(v11.0) King Activity.024\"; c0 \"Kh2=10, Kh1=4, Ra7=3\";", "2rk4/1Rp5/1bBp1r2/4p2p/8/6P1/P1P2P1P/5RK1 w - - bm Kg2; id \"STS(v11.0) King Activity.025\"; c0 \"Kg2=10, c4=4, h4=6\";", "3b4/3k1p2/4p1p1/p1rpP1Pp/R4P2/1P3K2/P2B1P2/8 b - - bm Kc6; id \"STS(v11.0) King Activity.026\"; c0 \"Kc6=10, Bb6=4, Kc8=5\";", "3b4/5p2/2k1p1p1/p1rpP1Pp/R4P2/1P6/P2BKP2/8 b - - bm Kb5; id \"STS(v11.0) King Activity.027\"; c0 \"Kb5=10, Bb6=6, Kb7=6\";", "3k1b1r/pp3p1p/5P2/3Bn3/8/2N5/PP5P/2K4R b - - bm Kc7; id \"STS(v11.0) King Activity.028\"; c0 \"Kc7=10, b6=4, Kc8=4\";", "3q1rk1/5p2/1pQ1p1p1/p2p4/P2P2P1/1P2P3/6RP/6K1 b - - bm Kg7; id \"STS(v11.0) King Activity.029\"; c0 \"Kg7=10, Kh7=3, Qe7=4, Qf6=4, Qh4=4\";", "3q4/p2r1k2/1p1b2nP/1Pp5/2P1Q3/1P2B3/3R1K2/8 w - - bm Kg1; id \"STS(v11.0) King Activity.030\"; c0 \"Kg1=10, Kf1=8\";", "3r1k2/4qp1p/6p1/p3p1P1/P2nQ2P/1B1R4/5PK1/8 b - - bm Kg7; id \"STS(v11.0) King Activity.031\"; c0 \"Kg7=10, Rc8=4, Rd7=4, Re8=4\";", "3r1k2/p4pp1/2n1p2p/1NPr4/P7/6P1/5P1P/2R1RK2 b - - bm Ke7; id \"STS(v11.0) King Activity.032\"; c0 \"Ke7=10, a6=3, g5=4, g6=4\";", "3r1r2/p3bpp1/1p2p1k1/4P2p/2P2P2/5K1P/PP3B2/3R1R2 b - - bm Kf5; id \"STS(v11.0) King Activity.033\"; c0 \"Kf5=10, f5=5, f6=1, Rfe8=5\";", "3r1r2/p3bppk/1p2p2p/4P3/2P2P2/8/PP3BKP/3R1R2 b - - bm Kg6; id \"STS(v11.0) King Activity.034\"; c0 \"Kg6=10\";", "3r2k1/1p4p1/p2P3p/1pPN4/1K4b1/8/2R4P/8 w - - bm Ka5; id \"STS(v11.0) King Activity.035\"; c0 \"Ka5=10, Rd2=5, Rf2=6, Rg2=5\";", "3r2k1/1rq2p2/2bp2pP/p3p2n/4P3/1BN2P2/1PP5/R2RQK2 b - - bm Kh7; id \"STS(v11.0) King Activity.036\"; c0 \"Kh7=10, Nf4=5, Ra7=2\";", "3r2k1/2p2ppp/8/P1b1N3/8/1Bn1nP2/5B1P/4K2R b - - bm Kf8; id \"STS(v11.0) King Activity.037\"; c0 \"Kf8=10, g6=3, Ncd5=1\";", "3r2k1/4pp1p/2q3p1/8/1P6/r1P2P2/P3Q1PP/RKR5 w - - bm Kb2; id \"STS(v11.0) King Activity.038\"; c0 \"Kb2=10, h3=6, Qe1=6, Qe4=5\";", "3r3r/ppk2pb1/4bn1p/3p2p1/3N4/2NR1BP1/PPP1P2P/5RK1 b - - bm Kb8; id \"STS(v11.0) King Activity.039\"; c0 \"Kb8=10, h5=2, Rhe8=1\";", "3r4/6p1/5kBp/7P/6P1/4BP2/1p2K3/8 b - - bm Ke5; id \"STS(v11.0) King Activity.040\"; c0 \"Ke5=10, Ke6=6, Rd5=7, Rd7=7\";", "3R4/6pk/p4p1p/1r1p3P/2pP4/2P1PN2/4bPP1/6K1 w - - bm Kh2; id \"STS(v11.0) King Activity.041\"; c0 \"Kh2=10, Kh1=2\";", "3r4/p3k3/1p2bpp1/2p5/2P2q2/2Q2N2/PP4PP/4R2K w - - bm Kg1; id \"STS(v11.0) King Activity.042\"; c0 \"Kg1=10, b3=9, h3=9, Qc2=9\";", "3rbk2/4pp1p/6p1/3PP3/p1PnN1P1/Nn5P/5PBK/1R6 w - - bm Kg3; id \"STS(v11.0) King Activity.043\"; c0 \"Kg3=10, Nc3=4, Re1=4\";", "3rbk2/5p1p/1p2p3/pP1nr1p1/P2RN1P1/3BP3/3K3P/3R4 b - - bm Ke7; id \"STS(v11.0) King Activity.044\"; c0 \"Ke7=10, Bd7=4, h6=6, Rd7=8\";", "3rr1k1/q4pp1/p1ppbR1p/2P4R/3PP3/2N1Q2P/6P1/6K1 b - - bm Kf8; id \"STS(v11.0) King Activity.045\"; c0 \"Kf8=10, dxc5=3\";", "3rr3/p1k4p/1p3p1b/2p2p1n/5P2/2P1BR2/PP1N3P/1K2R3 b - - bm Kc6; id \"STS(v11.0) King Activity.046\"; c0 \"Kc6=10, Kb7=5, Kc8=5\";", "4k3/1p4pp/p1b2p2/P4P2/1PNp2qN/2nP2P1/3Q1K1P/8 b - - bm Kd8; id \"STS(v11.0) King Activity.047\"; c0 \"Kd8=10, Kf8=2, Qd1=3\";", "4k3/3p3p/p2Pn1p1/Pr2Pp2/5P1P/1NR3P1/5K2/8 w - - bm Ke3; id \"STS(v11.0) King Activity.048\"; c0 \"Ke3=10, h5=7, Ke1=5, Rc8+=4, Rd3=3\";", "4r1k1/1p1q2pp/p4pn1/3p4/3N4/1PPK2RP/P2Q1PP1/8 w - - bm Kc2; id \"STS(v11.0) King Activity.049\"; c0 \"Kc2=10, Qc1=5, Qd1=5\";", "4r1k1/1Q3ppp/2PB4/pb6/8/P1K5/6P1/1r6 w - - bm Kc2; id \"STS(v11.0) King Activity.050\"; c0 \"Kc2=10, c7=7, Kd4=1\";", "4r1k1/2q1p3/2p2pp1/1p1b4/p7/P1Q3R1/1P3PP1/4R1K1 b - - bm Kg7; id \"STS(v11.0) King Activity.051\"; c0 \"Kg7=10, Bf7=8, g5=8, Kf7=8\";", "4r1k1/3b1q2/2pn1p1b/1p3P2/p2PN1PP/P4Q2/1P4R1/4R1K1 b - - bm Kf8; id \"STS(v11.0) King Activity.052\"; c0 \"Kf8=10\";", "4r1k1/5r2/p5p1/6p1/1PbB4/2P2B2/5PP1/R5K1 w - - bm Kh2; id \"STS(v11.0) King Activity.053\"; c0 \"Kh2=10, Be3=8, Ra5=6, Rd1=4\";", "4r1k1/p4p1p/1bpp2p1/3p4/8/1P1Q2P1/P1P1rPKP/5R2 w - - bm Kf3; id \"STS(v11.0) King Activity.054\"; c0 \"Kf3=10, Kg1=2, Qc3=2\";", "4r2r/1p6/2p2n2/p1Pp3k/P2NbPp1/4R3/1P2P2P/2R2BK1 b - - bm Kg6; id \"STS(v11.0) King Activity.055\"; c0 \"Kg6=10, Kh4=4, Ref8=3, Rh7=3\";", "4r3/2R1pk2/3p2pp/2bP1p2/8/1R4P1/5PK1/8 b - - bm Kf6; id \"STS(v11.0) King Activity.056\"; c0 \"Kf6=10, Bd4=8, g5=9, h5=8, Ra8=8\";", "4r3/5k2/2PB4/p4p2/8/1P1R2KP/2P5/5r2 w - - bm Kg2; id \"STS(v11.0) King Activity.057\"; c0 \"Kg2=10, Rd2=1\";", "4r3/5k2/3p1npp/1p1P1p2/p4P2/P3N2P/1P2KP2/2R5 w - - bm Kf3; id \"STS(v11.0) King Activity.058\"; c0 \"Kf3=10, h4=8, Kf1=8, Rc7+=8\";", "4r3/5k2/p2B2r1/2P2p2/1P5p/3R3P/1P3KP1/8 w - - bm Kf3; id \"STS(v11.0) King Activity.059\"; c0 \"Kf3=10\";", "4R3/5pkp/b3p1p1/2Q5/1P6/P2qP3/K7/8 w - - bm Kb2; id \"STS(v11.0) King Activity.060\"; c0 \"Kb2=10, Qc1=4\";", "4rbk1/p2R1p2/2p2p1p/5p2/8/PR2p3/2P3PP/5K2 w - - bm Ke2; id \"STS(v11.0) King Activity.061\"; c0 \"Ke2=10, g3=3, Rc3=3\";", "4rnk1/1p2rp1p/2p3p1/3p1B1P/N4R2/pP2P1R1/P5P1/6K1 w - - bm Kf2; id \"STS(v11.0) King Activity.062\"; c0 \"Kf2=10, e4=5, hxg6=7, Rff3=6\";", "4rrk1/7p/pn1p1npb/N2P4/1P6/5BP1/PB6/3R1RK1 w - - bm Kg2; id \"STS(v11.0) King Activity.063\"; c0 \"Kg2=10, Bxf6=2\";", "5bk1/1r3p2/6p1/2pRP3/8/6P1/3N1PK1/8 b - - bm Kg7; id \"STS(v11.0) King Activity.064\"; c0 \"Kg7=10\";", "5k2/p3np2/2b1p2p/2P2p1P/8/2N1PP2/2K1B1P1/8 b - - bm Ke8; id \"STS(v11.0) King Activity.065\"; c0 \"Ke8=10, Bd7=7, Nd5=8, Ng8=6\";", "5n2/1p2r1kp/1Qp1r1p1/p3Pp2/P6P/4R1P1/1P6/5K2 w - - bm Kg2; id \"STS(v11.0) King Activity.066\"; c0 \"Kg2=10, b3=6, Kg1=7, Re1=9, Re2=8\";", "5r2/1N6/2p2Pk1/p1P1P1p1/3b3p/KP1N2n1/P6R/8 b - - bm Kf5; id \"STS(v11.0) King Activity.067\"; c0 \"Kf5=10, Ne4=1, Nf1=1\";", "5rk1/1p5p/3p2p1/qP1N1n2/2P2P2/8/P4Q1P/4R1K1 w - - bm Kg2; id \"STS(v11.0) King Activity.068\"; c0 \"Kg2=10, Kf1=3, Kh1=5, Rc1=2, Re4=5\";", "5rrk/6qp/2R2b2/1P1pp2Q/5p2/7R/P2B1P2/5K2 w - - bm Ke2; id \"STS(v11.0) King Activity.069\"; c0 \"Ke2=10, Be1=9, Rc1=9, Rh1=9\";", "6k1/5b1p/6p1/r1P5/3pNK2/5P1P/p5P1/R7 b - - bm Kf8; id \"STS(v11.0) King Activity.070\"; c0 \"Kf8=10, h6=6, Kg7=4, Rb5=6\";", "6k1/8/p2Br1r1/2P2p1p/1P6/7P/1P1R2PK/8 w - - bm Kg1; id \"STS(v11.0) King Activity.071\"; c0 \"Kg1=10, Rc2=4, Rf2=2\";", "6r1/1b1k4/2p2p2/ppB1p3/2p1P2P/P2n4/1P1R2P1/5K1R b - - bm Ke6; id \"STS(v11.0) King Activity.072\"; c0 \"Ke6=10, Kc7=4, Ke8=2\";", "6r1/pb3pk1/1p2p3/1Bp1P3/2Pb4/P7/4RPPR/6K1 b - - bm Kf8; id \"STS(v11.0) King Activity.073\"; c0 \"Kf8=10, a6=8, Ba8=8, Rb8=7\";", "6rk/q2p3p/4pp2/1P1n3P/2R5/p4NP1/P4P2/1Q4K1 w - - bm Kg2; id \"STS(v11.0) King Activity.074\"; c0 \"Kg2=10, Nd4=4, Rd4=4\";", "7k/1b1n1pp1/p2Ppq1p/1p5Q/1P1N3P/P3P3/B5P1/6K1 b - - bm Kg8; id \"STS(v11.0) King Activity.075\"; c0 \"Kg8=10, Kh7=6, Nf8=1\";", "7k/1q5p/5prP/1p1pr3/1PbR1QPK/2N3P1/2P5/3R4 w - - bm Kh3; id \"STS(v11.0) King Activity.076\"; c0 \"Kh3=10, R1d2=8, Ra1=9, Rb1=8\";", "7k/3N1p2/p7/3p1rp1/8/1P2P2p/P4n2/2R2NK1 w - - bm Kh2; id \"STS(v11.0) King Activity.077\"; c0 \"Kh2=10, Ng3=6, Rc2=5, Rc8+=6\";", "7k/3r1p2/p1r1p2p/1q1n3P/1PNRQP2/P7/K7/2R5 w - - bm Kb2; id \"STS(v11.0) King Activity.078\"; c0 \"Kb2=10\";", "7r/5p2/3k4/1p1p4/rPnP3P/4P3/4RPN1/1R5K w - - bm Kh2; id \"STS(v11.0) King Activity.079\"; c0 \"Kh2=10, Kg1=7, Nf4=5, Rb3=4\";", "7r/r1p2k1p/1p5B/1bp5/4pPP1/1P2Nn1P/PR3R2/7K b - - bm Kg6; id \"STS(v11.0) King Activity.080\"; c0 \"Kg6=10, Ne1=2, Ra3=2, Rd8=1, Rha8=2\";", "8/1k1r3p/pp3p1R/2pn4/4r3/N1P5/PP5P/2KR4 b - - bm Kc7; id \"STS(v11.0) King Activity.081\"; c0 \"Kc7=10, b5=4, Ree7=4\";", "8/1p2bk2/r7/p2P4/2P5/4B1R1/PP4Pn/1K6 w - - bm Kc2; id \"STS(v11.0) King Activity.082\"; c0 \"Kc2=10, Bd2=2, Bd4=7, Bg1=8\";", "8/2kr3p/5p2/pppn4/4r3/1PP4R/P1N4P/2KR4 b - - bm Kc6; id \"STS(v11.0) King Activity.083\"; c0 \"Kc6=10, c4=4, Re2=5\";", "8/3k3p/2p2p2/2B5/8/1r1b1P1P/3R1KP1/8 b - - bm Ke6; id \"STS(v11.0) King Activity.084\"; c0 \"Ke6=10, Kc7=7, Ke8=7\";", "8/4q1k1/5pp1/pp2b3/2p1P3/P1P1Q1Pp/7P/3R2K1 w - - bm Kf1; id \"STS(v11.0) King Activity.085\"; c0 \"Kf1=10, Qd2=3, Rd5=4\";", "8/4r1n1/1k5p/1p1prp1P/1PpN2p1/p1K1P1R1/P1B3PR/8 w - - bm Kd2; id \"STS(v11.0) King Activity.086\"; c0 \"Kd2=10, Bb1=9, Rh1=9, Rh4=9\";", "8/4r2p/2k2p2/1p1nr3/1Pp5/2P2R2/2NR3P/1K6 b - - bm Kb6; id \"STS(v11.0) King Activity.087\"; c0 \"Kb6=10, f5=6, Rg7=5, Rh5=6\";", "8/p1r1rk1p/2R1pb2/P4p2/1N4p1/1Pp1P1P1/5P1P/2R3K1 w - - bm Kf1; id \"STS(v11.0) King Activity.088\"; c0 \"Kf1=10, a6=7, Kg2=7, Rd6=7, Rxc7=6\";", "8/p3p1k1/1p1p1pp1/4n3/3R3P/1Pr5/P5P1/3R2K1 b - - bm Kh6; id \"STS(v11.0) King Activity.089\"; c0 \"Kh6=10, a5=8, f5=8, Rc2=6\";", "8/pQ3qk1/P2pp2p/2p2n2/2P2PB1/3P3P/8/7K b - - bm Kf6; id \"STS(v11.0) King Activity.090\"; c0 \"Kf6=10, h5=7, Kf8=7, Ng3+=6\";", "8/pr3pbk/6p1/7p/R7/2p1P1P1/2R2P1P/6K1 w - - bm Kf1; id \"STS(v11.0) King Activity.091\"; c0 \"Kf1=10, Kg2=4, Ra5=4\";", "8/R2n4/pr1k2p1/4pp1p/5P2/1N2P1PP/Pn2B1K1/8 w - - bm Kf1; id \"STS(v11.0) King Activity.092\"; c0 \"Kf1=10, Bxa6=3, Kf2=4, Kh2=3\";", "b2q2r1/5p2/2prpkp1/1pN5/p2P1PP1/P3PQ1p/1PB4P/2R3K1 b - - bm Kg7; id \"STS(v11.0) King Activity.093\"; c0 \"Kg7=10, Ke7=4, Qa5=6, Re8=5, Rh8=4\";", "br3rk1/2q1bpp1/pnnpp2p/1p3P2/4P3/PNN1BBQ1/1PPR2PP/1R4K1 b - - bm Kh7; id \"STS(v11.0) King Activity.094\"; c0 \"Kh7=10, Bf6=4, Kh8=8\";", "r1b3qr/3kppb1/p2p4/2pPn1B1/1pP1P3/1N5P/1P2BQP1/1R3RK1 b - - bm Ke8; id \"STS(v11.0) King Activity.095\"; c0 \"Ke8=10\";", "r2r2k1/p4pp1/b6p/8/1pp1Pn2/4NP2/PPB3PP/3RR1K1 w - - bm Kf2; id \"STS(v11.0) King Activity.096\"; c0 \"Kf2=10, g3=4, Nd5=2\";", "r2r4/5qbk/2p3pp/pp2p3/Pn1P1p1Q/4P2N/1P1N1PPP/2RR2K1 b - - bm Kg8; id \"STS(v11.0) King Activity.097\"; c0 \"Kg8=10, Bf6=7, Qe8=2, Qf6=6\";", "r4b1r/pp1k1pp1/4bn1p/3p4/4p3/1NN3P1/PPP1PPBP/3R1RK1 b - - bm Kc7; id \"STS(v11.0) King Activity.098\"; c0 \"Kc7=10, Kc6=7, Ke8=7\";", "r5k1/4pp1p/6p1/3q4/1P6/r1P2P2/PKR1Q1PP/R7 w - - bm Kc1; id \"STS(v11.0) King Activity.099\"; c0 \"Kc1=10, Kb1=3, Kb1=9\";", "R7/2k5/2p2p2/4p3/1pp1P1b1/n7/6P1/2R2K2 b - - bm Kb6; id \"STS(v11.0) King Activity.100\"; c0 \"Kb6=10\";", "1k1r4/4bp2/p1q1pnr1/6B1/NppP3P/6P1/1P3P2/2RQR1K1 w - - bm Re5; id \"STS(v12.0) Center Control.001\";", "1k5r/1pq1b2r/p2p1p2/4n1p1/R3P1p1/1BP3B1/PP1Q3P/1K1R4 w - - bm Bd5; id \"STS(v12.0) Center Control.002\";", "1kb4r/1p3pr1/3b1p1p/q2B1p2/p7/P1P3P1/1P1Q2NP/K2RR3 b - - bm Be5; id \"STS(v12.0) Center Control.003\";", "1kr5/1b3ppp/p4n2/3p4/2qN1P2/2r2B2/PQ4PP/R2R3K b - - bm Ne4; id \"STS(v12.0) Center Control.004\";", "1n1r4/p1q2pk1/b2bp2p/4N1p1/3P1P2/1QN1P3/5PBP/1R5K w - - bm Ne4; id \"STS(v12.0) Center Control.005\";", "1n1rr1k1/1pq2pp1/3b2p1/2p3N1/P1P5/P3B2P/2Q2PP1/R2R2K1 w - - bm Ne4; id \"STS(v12.0) Center Control.006\";", "1n1rr1k1/5pp1/1qp4p/3p3P/3P4/pP1Q1N2/P1R2PP1/1KR5 w - - bm Ne5; id \"STS(v12.0) Center Control.007\";", "1r1r1bk1/1bq2p1p/pn2p1p1/2p1P3/5P2/P1NBB3/1P3QPP/R2R2K1 b - - bm Nd5; id \"STS(v12.0) Center Control.008\";", "1r2qrk1/2p3pp/2Qb1p2/2p1pP2/8/BP6/3P1PPP/R4RK1 w - - bm Qe4; id \"STS(v12.0) Center Control.009\";", "1r2qrk1/4n3/ppbp3p/n1p1p1p1/2P5/B1PP2PP/Q2N1PB1/1R2R1K1 w - - bm Ne4; id \"STS(v12.0) Center Control.010\";", "1r3b2/3R2pk/6q1/3Q1p2/p6P/4B2P/1P3P1K/8 w - - bm Bd4; id \"STS(v12.0) Center Control.011\";", "1r3r1k/6pp/p2p4/q3pb2/2P4P/1P2Q1P1/P4PB1/R4K1R w - - bm Bd5; id \"STS(v12.0) Center Control.012\";", "1r3r1k/7p/p1p1q3/1pP1P3/3P4/Pb6/3Q2BP/2R1R1K1 b - - bm Bd5; id \"STS(v12.0) Center Control.013\";", "1r4k1/p1rnpp2/p2p1bp1/2qP4/4PQ2/1PN4P/P2B2P1/1R3R1K b - - bm Qd4; id \"STS(v12.0) Center Control.014\";", "1rb2rnk/2qn4/pp1p3p/2pP1p2/PPPbp2B/1QN5/R2NBPPP/1R4K1 b - - bm Ne5; id \"STS(v12.0) Center Control.015\";", "2b2q1k/2p4p/1rNn1p2/1p1P4/p3p3/P1P5/1P1Q2PP/1B1R2K1 w - - bm Qd4; id \"STS(v12.0) Center Control.016\";", "2b3k1/1q3pp1/p2R3p/8/Q7/2P1r3/6PP/R5K1 w - - bm Qd4; id \"STS(v12.0) Center Control.017\";", "2br4/2q2k1p/p2bp1p1/1r6/4BP2/2p1B3/P3Q1PP/2R2R1K w - - bm Bd4; id \"STS(v12.0) Center Control.018\";", "2q1rbk1/1b3p2/p4Pp1/1p1p3p/3B4/1P1Q1N1P/1P3PP1/R5K1 w - - bm Ne5; id \"STS(v12.0) Center Control.019\";", "2r1r1k1/p1qn1pp1/1p3n1p/3p4/3P3B/P1NQ4/1P3PPP/2RR2K1 b - - bm Ne4; id \"STS(v12.0) Center Control.020\";", "2r1rbk1/pp2p2p/6p1/n4p2/1NbP4/4PBBP/P4PP1/2RR2K1 w - - bm Nd5; id \"STS(v12.0) Center Control.021\";", "2r2k2/p1q1bpp1/2p2n2/2Np3r/1P5p/P1Q1B2P/5PP1/2R1R1K1 w - - bm Bd4; id \"STS(v12.0) Center Control.022\";", "2r2rk1/1p3ppp/p2q1n2/3pn3/N7/4P2P/PP2BPP1/2RQ1RK1 w - - bm Qd4; id \"STS(v12.0) Center Control.023\";", "2r2rk1/1pp2qpb/1n2p2p/pP1p1P2/P2PPBP1/7P/3NQ3/R1R3K1 w - - bm Be5; c0 \"Be5=10, Bg3=4, Ra3=4, Rf1=4\"; id \"STS(v12.0) Center Control.024\";", "2r3k1/1b2q1pp/1pr1p3/4B3/2P1p3/4P3/4QPPP/1R1R2K1 w - - bm Rd4; c0 \"Rd4=10, h3=2, h4=2, Qg4=2\"; id \"STS(v12.0) Center Control.025\";", "2r3k1/p2npp2/p2p1bp1/3P4/1qN1PQ1P/1P2B3/r5P1/1R3R1K b - - bm Ne5; c0 \"Ne5=10, a5=7, Bd4=10Qb8=6, Rc7=6\"; id \"STS(v12.0) Center Control.026\";", "2r3k1/ppr2p2/4b2p/4b1p1/P7/2N1P3/1PB2PPP/2RRK3 w - - bm Be4; c0 \"Be4=10, Bd3=6, h3=6, Rd3=6\"; id \"STS(v12.0) Center Control.027\";", "2r4k/5p1p/1prp1q1P/2n1p1p1/p3P1P1/P3BP2/1PP5/1KRR3Q w - - bm Rd5; c0 \"Rd5=10, Qg2=3, Qh3=7, Qh5=5, Re1=6, Rf1=7\"; id \"STS(v12.0) Center Control.028\";", "2r5/1b2kp1p/3qp1p1/1B6/3pn2N/8/PP2QPPP/4R1K1 b - - bm Qd5; c0 \"Qd5=10, Nf6=4, Qf4=5, Rc5=4\"; id \"STS(v12.0) Center Control.029\";", "2r5/1bq2k2/p2pp2r/5p2/2PN1Pp1/1PB1Q3/P5PP/4R1K1 b - - bm Be4; c0 \"Be4=10, g3=1, Qc5=1, Qd7=2\"; id \"STS(v12.0) Center Control.030\";", "2rq1k1r/pp3p2/7p/1BPp1bp1/1P6/P1N1P3/3Q1PPP/2R1K2n w - - bm Qd4; c0 \"Qd4=10, Ke2=4, Kf1=5, Nxd5=5\"; id \"STS(v12.0) Center Control.031\";", "2rq1rk1/p3b1pp/2p1p3/8/P2Pp3/1P1bP1P1/3B3P/2RQRBK1 b - - bm Qd5; c0 \"Qd5=10, Bxf1=1, e5=1\"; id \"STS(v12.0) Center Control.032\";", "2rq1rk1/pb2bppp/1p2pn2/4N3/3P1B2/2PB4/P4PPP/2RQR1K1 b - - bm Qd5; c0 \"Qd5=10, Ba3=7, Nd5=7, Rc7=6\"; id \"STS(v12.0) Center Control.033\";", "2rq1rk1/pb3ppp/1p1p1b2/2n1p3/P1B1P3/1P3N2/2P1RPPP/R1BQ2K1 w - - bm Bd5; c0 \"Bd5=10, Bb2=6, Nd2=3, Rb1=5\"; id \"STS(v12.0) Center Control.034\";", "2rr4/p1N1pk1p/1p4pb/n4p2/2bP4/4PB1P/P1R2PPB/3R2K1 w - - bm d5; c0 \"d5=10, Be5=4, Rdc1=5\"; id \"STS(v12.0) Center Control.035\";", "3r1bk1/3q1p2/4bP1p/pp4pP/2pP4/2P3B1/P1Q3P1/4RRK1 w - - bm Re5; c0 \"Re5=10, a3=1, Re3=4, Rf3=3\"; id \"STS(v12.0) Center Control.036\";", "3r1qk1/6pp/1p1np3/2n4Q/p7/P3N1P1/1B2PP1P/3R2K1 w - - bm Rd4; c0 \"Rd4=10, Bd4=6, f3=3, Nc4=5, Qg4=4, Qh4=3\"; id \"STS(v12.0) Center Control.037\";", "3r1r2/2n3kp/1pp1p1p1/p2nP3/P7/2NR2PB/1P3P1P/3R2K1 w - - bm Ne4; c0 \"Ne4=10, f4=4, Rd4=3\"; id \"STS(v12.0) Center Control.038\";", "3r1r2/2p3k1/1p3b1p/p7/2P1qP1P/1P1R2P1/P4P2/1Q1R2K1 b - - bm Bd4; c0 \"Bd4=10, Rde8=2, Rf7=2, Rxd3=2\"; id \"STS(v12.0) Center Control.039\";", "3r2k1/1p1b1pp1/p1q4p/8/2nNRB2/2P3P1/P4P1P/4Q1K1 b - - bm Qd5; c0 \"Qd5=10, Qb6=2, Qc5=3, Qc8=2\"; id \"STS(v12.0) Center Control.040\";", "3r2k1/3r1pp1/2QP4/pP5p/1qN5/4R1P1/4PK1P/8 w - - bm Re4; c0 \"Re4=10, Rd3=1\"; id \"STS(v12.0) Center Control.041\";", "3r2k1/3r2p1/2q1p2p/1p1n1p2/p7/P3RQ1P/BPP2PP1/3R2K1 w - - bm Re5; c0 \"Re5=10, h4=3, Rd2=3, Rde1=2, Ree1=1\"; id \"STS(v12.0) Center Control.042\";", "3r2r1/BpqP1pkp/6p1/3Qb3/8/2p3P1/PP1R1PBP/5K2 w - - bm Bd4; c0 \"Bd4=10, Bb6=3, bxc3=7, Rd1=5\"; id \"STS(v12.0) Center Control.043\";", "3r4/1p4kp/p1b3p1/2q1p3/P1P5/1B3P1P/4Q1P1/1R5K b - - bm Rd4; c0 \"Rd4=10, a5=3, b6=4, Kf6=4, Kf7=4\"; id \"STS(v12.0) Center Control.044\";", "3rbk2/4np1p/1p2p3/pP2r1p1/P1R1N1P1/3BP3/3K3P/3R4 b - - bm Nd5; c0 \"Nd5=10, Bd7=3, h6=4, Kg7=4\"; id \"STS(v12.0) Center Control.045\";", "4k3/p1p3p1/1pbp2qp/n3p3/2P3PB/2PPQ2P/P3P1B1/6K1 w - - bm Bd5; c0 \"Bd5=10, Bf1=5, Bf2=5, Bxc6+=7\"; id \"STS(v12.0) Center Control.046\";", "4r1k1/1b3pp1/p2pqb2/1p4r1/4PR2/PNN4P/1PP2QP1/5R1K w - - bm Nd4; c0 \"Nd4=10, Nd5=1, Qb6=3\"; id \"STS(v12.0) Center Control.047\";", "4r1k1/1pb1qp2/p1b3p1/3p1rN1/P4P1p/1PPRB1P1/3Q3P/3R2K1 w - - bm Bd4; c0 \"Bd4=10, Bf2=4, Nf3=3, Re1=4, Rf1=4\"; id \"STS(v12.0) Center Control.048\";", "4r1k1/3r1p1p/3p2p1/3P2Q1/4PR2/2n2B1P/5qPK/R7 b - - bm Qd4; c0 \"Qd4=10, Qd2=1, Qe3=1, Ra8=6, Rb7=1\"; id \"STS(v12.0) Center Control.049\";", "4r1k1/4r1pp/p7/3n4/2p1P3/2P1BPN1/P1P4P/1K2R3 w - - bm Bd4; c0 \"Bd4=10, Bd2=7, Kc1=7, Nf5=7\"; id \"STS(v12.0) Center Control.050\";", "4r1k1/p5b1/P2p1pp1/q1pP3p/2Pn1BbP/2NP2P1/3Q2BK/1R6 w - - bm Ne4; c0 \"Ne4=10, Be5=7, Kh1=6, Nb5=10Rb7=7\"; id \"STS(v12.0) Center Control.051\";", "4r1k1/pb2qp1p/4n2P/3p1pP1/1P1N1Q2/2N5/P1P5/5R1K w - - bm Qe5; c0 \"Qe5=10, Qd2=1\"; id \"STS(v12.0) Center Control.052\";", "4r1k1/R3rpp1/1p3n1p/8/2Q5/4B2P/1q3PP1/3R2K1 w - - bm Bd4; c0 \"Bd4=10, Raa1=3, Rxe7=2\"; id \"STS(v12.0) Center Control.053\";", "4r2k/1q4p1/p2Bp2p/P3P3/1PpN2P1/2Pb2b1/Q7/K2R4 b - - bm Qe4; c0 \"Qe4=10, Qa8=2, Qd7=1, Qf7=1\"; id \"STS(v12.0) Center Control.054\";", "4r3/p4pk1/3p1n1p/1P4p1/4q3/1P4P1/1N1QP2P/4R1K1 b - - bm Qe5; c0 \"Qe5=10, d5=4, Qf5=4, Rb8=4\"; id \"STS(v12.0) Center Control.055\";", "5n2/kbr3p1/5n1p/Pp2pP2/4P1PP/2p5/P1Br4/2RNRNK1 b - - bm Rd4; c0 \"Rd4=10, Ka6=5, Rd8=2, Rdd7=2\"; id \"STS(v12.0) Center Control.056\";", "5r1k/p1r3np/1p3q2/2p4P/2Q2P2/8/PPB5/1K1R1R2 w - - bm Rd5; c0 \"Rd5=10, f5=2, Rfe1=2, Rg1=2\"; id \"STS(v12.0) Center Control.057\";", "5rk1/p3pp1p/2Q2bp1/q1P5/3p4/5BP1/Pr2PP1P/2RR2K1 w - - bm Qe4; c0 \"Qe4=10, a4=6, h4=6, Kg2=3\"; id \"STS(v12.0) Center Control.058\";", "5rk1/pb3ppp/1p3q2/2n5/2B1p3/2P5/P3QPPP/R2R2K1 w - - bm Rd4; c0 \"Rd4=10, a4=4, Bd5=5, Qe1=4, Qe3=5, Rac1=4\"; id \"STS(v12.0) Center Control.059\";", "5rk1/qbrpnppp/p3p3/P2nP3/Np6/1N1B4/1PPQ1PPP/3RR1K1 w - - bm Re4; c0 \"Re4=10, c3=2, c4=2, g3=2\"; id \"STS(v12.0) Center Control.060\";", "5rqk/3b2pp/1pnNp3/3r4/6P1/PQ2B1RP/5PK1/3R4 b - - bm Ne5; c0 \"Ne5=10, Na5=7, Ne7=7, Rxd1=6\"; id \"STS(v12.0) Center Control.061\";", "6k1/1p2p3/2n1P2p/p3b3/2P2p2/1P4qP/P7/1B3QBK w - - bm Be4; c0 \"Be4=10, Bf2=4, Qg2=2\"; id \"STS(v12.0) Center Control.062\";", "6k1/1p3pp1/p3q2p/3p3P/1Pn2Q2/P3PP2/4NKP1/8 w - - bm Qd4; c0 \"Qd4=10, g4=2\"; id \"STS(v12.0) Center Control.063\";", "6k1/4qp2/p6p/1p6/2n2p2/P4Q2/1P4PP/6BK b - - bm Qe5; c0 \"Qe5=10, Qd6=3, Qf6=4, Qg5=1\"; id \"STS(v12.0) Center Control.064\";", "6k1/5p2/p3b2p/1pp4q/4Pp2/1P3P2/P1Q3PP/3B1K2 b - - bm Qe5; c0 \"Qe5=10, c4=2, f6=1, Kh8=3\"; id \"STS(v12.0) Center Control.065\";", "7k/1qr2p2/p3p2p/P1b1P1p1/2Q1n3/1p2BN1P/1P3PP1/2R3K1 w - - bm Nd4; c0 \"Nd4=10, Bd4=1, Kf1=1, Kh2=1\"; id \"STS(v12.0) Center Control.066\";", "8/2p1r1pk/2pq2bp/2p5/2P3Q1/pP1P2NP/P3PRK1/8 b - - bm Qe5; c0 \"Qe5=10, Qd8=7, Re5=7, Re6=7\"; id \"STS(v12.0) Center Control.067\";", "8/3n1kpp/1pr1p3/2n5/pR6/P3NPP1/1B2PK1P/8 w - - bm Bd4; c0 \"Bd4=10, f4=4, Nc4=4, Ng4=4\"; id \"STS(v12.0) Center Control.068\";", "8/6k1/1b1p1pp1/1b1Pp3/2q1P3/6P1/2B2PKN/3Q4 b - - bm Qd4; c0 \"Qd4=10, Bc5=4, Bd4=4, Qa2=4\"; id \"STS(v12.0) Center Control.069\";", "8/pp2r1kp/2prP3/5R2/2P5/3n2P1/P5BP/1R5K w - - bm Be4; c0 \"Be4=10, Bd5=6, Bf1=7, Rb3=7, Rf3=7\"; id \"STS(v12.0) Center Control.070\";", "b4rk1/8/4pr1p/2q5/P4p2/2PB4/6PP/R3QR1K w - - bm Be4; c0 \"Be4=10, Be2=2, Qe4=5, Rb1=4, Rd1=3, Rg1=2\"; id \"STS(v12.0) Center Control.071\";", "brr1n1k1/4bpp1/q2p4/Np2n3/1P1RP2p/2N4P/2P3PB/3RQB1K w - - bm Nd5; c0 \"Nd5=10, Be2=1, Qd2=1, Ra1=1\"; id \"STS(v12.0) Center Control.072\";", "k2r4/2q3p1/p1Pr1p2/P1R1p2P/5pP1/8/1PQp1P2/1K1R4 b - - bm Rd4; c0 \"Rd4=10, Ka7=6, Kb8=6, Rd3=6\"; id \"STS(v12.0) Center Control.073\";", "nr2q1k1/1p2rpb1/p2p2pp/P7/1PRN4/4BBPb/3Q1P1P/2R3K1 w - - bm Bd5; c0 \"Bd5=10, Kh1=5, Ne2=6, R4c2=5\"; id \"STS(v12.0) Center Control.074\";", "r1q1r1k1/1p2b1pp/2p1P1b1/3p1p2/p2N1B2/P1Q1PP1P/1P4P1/2RR2K1 w - - bm Be5; c0 \"Be5=10, Kf2=1, Kh2=2, Rd2=2\"; id \"STS(v12.0) Center Control.075\";", "r1q3k1/p2rnpb1/1pnBb1pp/2p1P3/6P1/2N2N1P/PP2QPB1/R2R2K1 w - - bm Qe4; c0 \"Qe4=10, Qe3=4, Rac1=5, Rd2=5\"; id \"STS(v12.0) Center Control.076\";", "r1r3k1/pb3p1p/1pqBp1p1/4P3/3b4/2P2P2/PR1N2PP/2RQ3K w - - bm Ne4; c0 \"Ne4=10, Qe2=3, Rbb1=1, Rbc2=1\"; id \"STS(v12.0) Center Control.077\";", "r2q1rk1/pp3pbp/3P2p1/4nb2/2p2N2/4B1P1/PP3PBP/R2Q1RK1 w - - bm Qd5; c0 \"Qd5=10, b3=2, Rc1=2, Re1=1\"; id \"STS(v12.0) Center Control.078\";", "r2q3r/1p3pk1/2b1p1p1/2R1P2p/p2P1P1R/P1Q1N1P1/1P3K2/8 b - - bm Be4; c0 \"Be4=10, Rc8=4\"; id \"STS(v12.0) Center Control.079\";", "r2qk2r/3nbpp1/2bBp2p/p3P3/1p6/8/PPPQBPPP/1NKR3R w kq - bm Qd4; c0 \"Qd4=10, f4=5, Qe3=7, Rhg1=5\"; id \"STS(v12.0) Center Control.080\";", "r2r2k1/p2n1p2/4q2p/3p2p1/1PpB4/P1NnPP2/2Q3PP/R2R2K1 b - - bm N7e5; c0 \"N7e5=10, a5=6, a6=6, Nb8=5\"; id \"STS(v12.0) Center Control.081\";", "r2r2k1/pN3p1p/2n1pp2/4q3/2P1P3/1Q6/P4PPP/R4RK1 b - - bm Rd4; c0 \"Rd4=10, Rd2=6, Rd7=7, Rdb8=6\"; id \"STS(v12.0) Center Control.082\";", "r3k2r/2qb1ppp/p3p3/2PpP3/2p2P2/P1P5/4B1PP/1R1Q1RK1 w kq - bm Qd4; c0 \"Qd4=10, c6=7, Rb2=7, Rb6=7\"; id \"STS(v12.0) Center Control.083\";", "r3kb1r/3n1ppp/p1bPp3/1q6/Npp1BB2/8/PP3PPP/2RQR1K1 w kq - bm Qd4; c0 \"Qd4=10, b3=2, Bxc6=4, Qc2=3, Qf3=7\"; id \"STS(v12.0) Center Control.084\";", "r3q1k1/p3r1p1/3R3p/2p5/1p2P3/1P4P1/P1Q4P/4R1K1 b - - bm Re5; c0 \"Re5=10, Qb5=5, Qh5=5, Rc8=4\"; id \"STS(v12.0) Center Control.085\";", "r3qrk1/4bpp1/Rp2pn1p/2p1N3/3P4/2P1P1B1/4QPPP/3R2K1 b - - bm Ne4; c0 \"Ne4=10, cxd4=2, Nd5=1, Rxa6=1\"; id \"STS(v12.0) Center Control.086\";", "r3r1k1/1b2qpp1/p3pn1p/1pPp4/PP1Q3P/1B2PPB1/6P1/R3K2R w KQ - bm Be5; c0 \"Be5=10, axb5=3, Bd6=3, Qb2=3\"; id \"STS(v12.0) Center Control.087\";", "r3r1k1/pp2qpb1/1n2b1pp/8/5B2/1P3NP1/P4PBP/R2QR1K1 w - - bm Be5; c0 \"Be5=10, Bd6=6, Nd2=6, Rc1=2\"; id \"STS(v12.0) Center Control.088\";", "r3r3/2q1bp1k/2N3pp/p1p5/Pp2Q3/4P3/1P3PPP/2RR2K1 w - - bm Qd5; c0 \"Qd5=10, Nxe7=6, Qf3=5\"; id \"STS(v12.0) Center Control.089\";", "r4r1k/p5p1/1qp1bp1p/8/3N4/P1Q1P3/1P4PP/2R2RK1 b - - bm Bd5; c0 \"Bd5=10, Bd7=4, Bf7=5, Bg8=5\"; id \"STS(v12.0) Center Control.090\";", "r4rk1/1pp2qpb/1n2p2p/pP1p1P2/P2PPBP1/7P/3NQ3/R3R1K1 w - - bm Be5; c0 \"Be5=10, Bg3=3, Ra3=3, Rac1=2, Rec1=2, Rf1=1\"; id \"STS(v12.0) Center Control.091\";", "r4rk1/2pb2b1/np1p3p/3P1p2/1PP1pP1q/4B3/2QNN1PP/1R3RK1 w - - bm Bd4; c0 \"Bd4=10, Nd4=1, Rf2=3\"; id \"STS(v12.0) Center Control.092\";", "r4rk1/pb1p2pp/1q1Ppn2/2p5/2P2P2/3BB3/PP2Q1PP/R3K2R b KQ - bm Be4; c0 \"Be4=10, Ne4=6, Qxd6=6, Rab8=6\"; id \"STS(v12.0) Center Control.093\";", "r5k1/3pppbp/6p1/4n3/1q2P3/4B3/P4PPP/2RQ1K1R w - - bm Qd5; c0 \"Qd5=10, h4=1, Qc2=4\"; id \"STS(v12.0) Center Control.094\";", "r5k1/8/r6p/P1q1p3/5p2/2P5/6PP/R3QR1K w - - bm Qe4; c0 \"Qe4=10, Qb1=2, Rb1=2, Rd1=1\"; id \"STS(v12.0) Center Control.095\";", "r5k1/p2b1pbp/6p1/2p5/1nn5/2N3P1/PP1N1P1P/R1B2RK1 b - - bm Ne5; c0 \"Ne5=10, Nb6=2, Nc2=2\"; id \"STS(v12.0) Center Control.096\";", "r5r1/1pp4p/2bn1k1B/p1p1p3/5PP1/1P5P/P1P1R3/R3N1K1 b - - bm e4; c0 \"e4=10, exf4=3, Kg6=2, Nf7=2, Rae8=3\"; id \"STS(v12.0) Center Control.097\";", "r6k/pp1q1pp1/1n6/1pQp4/3Pr2p/P2NP2P/5PP1/2R2RK1 w - - bm Ne5; c0 \"Ne5=10, Qb4=3, Qc7=4, Rb1=4\"; id \"STS(v12.0) Center Control.098\";", "r6r/4kp2/1qbp1p1b/p3pP1N/1pB1P2p/8/PPP1Q1PP/1K2R2R b - - bm Qd4; c0 \"Qd4=10, Bg5=3, Qc5=3, Rac8=3\"; id \"STS(v12.0) Center Control.099\";", "r7/4kp2/3Rp2b/2p1P3/bp3P1P/rB2N3/P1P5/1K1R4 w - - bm Bd5; c0 \"Bd5=10, Nc4=2\"; id \"STS(v12.0) Center Control.100\";", "1k1r4/1p3p2/p1bq1p1p/4p3/3r1P1Q/P5P1/1PP1B2P/K2RR3 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.001\"; c0 \"e4=10, Qc5=7, Qe6=7, Qe7=7, Re8=7\";", "1k2r1r1/ppp1q1b1/nn1pp3/1N3p1p/1PP2P2/PQ2B1PB/4PK1P/3R2R1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.002\"; c0 \"e5=10, Rgf8=3\";", "1kr3r1/1p1nqp2/p2p4/3PpBp1/1PP5/5R1P/P3QP2/R5K1 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.003\"; c0 \"e4=10\";", "1q1r2k1/3n1bp1/1p2pp2/pNn5/P3PP2/1P2QB2/6NP/3R2K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.004\"; c0 \"e5=10, Be2=5, Nd4=6, Nd6=3, Rb1=7\";", "1q2rrk1/p5bp/2p1p1p1/3p4/5P2/4QBP1/PPP2R1P/1R4K1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.005\"; c0 \"e5=10, a6=1, Qc7=2, Rf7=1\";", "1qr1r1k1/5pp1/1p2p2p/1Qbn3b/2R5/3P1NPP/3NPPB1/1R4K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.006\"; c0 \"e4=10, d4=2, Ne4=2, Rbc1=1\";", "1qr1r3/5ppk/1p2p2p/1Qbn3b/2R5/3P1NPP/3NPPB1/1R5K w - - bm d4; id \"STS(v13.0) Pawn Play in the Center.007\"; c0 \"d4=10, e3=3, Kg1=3, Ne4=4\";", "1r1r2k1/1p3pp1/pNn1b2p/3p1q2/5B2/P7/1P1Q1PP1/2R1R1K1 b - - bm d4; id \"STS(v13.0) Pawn Play in the Center.008\"; c0 \"d4=10, Kh7=1\";", "1r1r2k1/p1R2ppp/1p6/2n1p1q1/3P4/Q4PP1/PP2B2P/3R2K1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.009\"; c0 \"d5=10\";", "1r1rb1k1/2q1bp1p/3ppnp1/8/pn1NPP2/2N2R1P/1PP1B1P1/2QR2BK b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.010\"; c0 \"d5=10, e5=2, Nc6=2\";", "1r2r1k1/2qn1pb1/3p2pp/p1pP4/PpQ1PP2/1P4PP/1B4B1/3RR1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.011\"; c0 \"e5=10, Ba1=8, Bc1=8, Bxg7=9\";", "1r2r1k1/p2bp1b1/2p1nnpp/qpP2p2/3P3P/P1N1PBPN/1BQ2P2/1R2R1K1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.012\"; c0 \"d5=10, Na2=4, Rec1=4, Red1=4\";", "1r2r2k/5pp1/1n2qn1p/3p4/p1pR4/Q3PBNP/PP3PP1/3R2K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.013\"; c0 \"e4=10, Ne2=5, Nh5=4, Qc3=6\";", "1r3k1r/1q2bpp1/4pn2/1p4p1/p1pPP1P1/P3P2P/1PQ4R/K1R1BB2 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.014\"; c0 \"e5=10, Bg2=8, Bg3=8, d5=6, Qe2=8\";", "1r3rk1/1p1qbbp1/2n1pn1p/1Np5/2P5/2BPP1PB/2N1Q2P/1R3RK1 w - - bm d4; id \"STS(v13.0) Pawn Play in the Center.015\"; c0 \"d4=10, Bg2=1, Ne1=2\";", "1r3rk1/1p3ppp/pN2bn2/P1p5/4P3/2P5/1P2B1PP/R4RK1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.016\"; c0 \"e5=10, Bf3=2, Rad1=1, Rfe1=1\";", "1r4k1/1br3p1/1ppbp3/p2p1q1p/P1PP1Pp1/1P2P1P1/1Q3NBP/2RR2K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.017\"; c0 \"e4=10, cxd5=3, Nd3=6, Qa2=5, Qe2=9\";", "1r6/pp1rqpbk/6p1/P2Bpb2/2P4p/1QN1P1P1/P2R1PKP/3R4 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.018\"; c0 \"e4=10, Bh6=7, h3+=7, hxg3=6, Rbd8=7, Rdd8=7\";", "1rb1r1k1/2n1ppbp/pq1p2p1/1ppP4/2P1PP2/NP3B1P/P2B1QP1/2R1R1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.019\"; c0 \"e5=10, Kh1=1\";", "1rb2r1k/2q1bppp/p1pppn2/P7/4P3/1PNQ4/2P1BPPP/R1B3RK b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.020\"; c0 \"d5=10\";", "1rb2rk1/2q2pb1/3p1np1/1pnP2Bp/4P3/1pN2PN1/3QB1PP/1RR3K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.021\"; c0 \"e5=10, Be3=7, Kh1=7, Nxb5=7\";", "1rnr2k1/2Rb2bp/3p2p1/2pPpp2/1p5P/1P1PP1P1/3B1PK1/R4BN1 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.022\"; c0 \"e4=10, Bb5=9, Be8=9, h6=8\";", "1rnrbk2/2R3bp/3p2p1/1ppPpp2/7P/3PP1P1/1P1B1PK1/R2N1B2 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.023\"; c0 \"e4=10, Kf3=1\";", "1rr5/p2bppkp/3p1np1/p1p5/Pq1PP3/1P2QN1P/2P1NPP1/2R1R1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.024\"; c0 \"e5=10, dxc5=4, Rcd1=1, Red1=3\";", "2b1k1r1/3nppb1/2pp1npp/qp6/3PP2B/1RNB1N2/P1PQ1PPP/7K w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.025\"; c0 \"e5=10, h3=2\";", "2b1r1k1/pp2rppp/2p3q1/3p4/1P1P4/P1N1PP2/5QPP/4RRK1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.026\"; c0 \"e4=10, Nd1=8, Qd2=8, Qe2=7, Rc1=8\";", "2br1r1k/4b1pp/pq2pn2/2p5/Pp2PN2/1B2BP2/1PQ2P1P/R5RK b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.027\"; c0 \"e5=10, a5=7, Qc6=7, Qd6=7\";", "2kr4/1p3p2/p1bqpp1p/8/3r1P1Q/3B2P1/PPP4P/K2RR3 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.028\"; c0 \"e5=10, Bf3=9, f5=7, Qe7=7\";", "2r1r1k1/1pqn1pp1/p2b1n1p/P2Ppb2/R7/2NNB3/1PPQBPPP/3R2K1 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.029\"; c0 \"e4=10, Bh7=6, Nf8=6, Qb8=7, Qd8=7\";", "2r1r1k1/3n2pp/b1p1pb2/1pPp1p1q/p2PnB1P/P4NP1/1PQNPPB1/R2R1K2 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.030\"; c0 \"e5=10, Bb7=1, h6=1, Kh8=1\";", "2r1r1k1/5npp/3q4/1QpP1p2/1p6/4PP2/1B2R1PP/2R3K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.031\"; c0 \"e4=10, h3=6, Qd3=8, Rec2=8, Ree1=7\";", "2r1r1k1/qp2ppb1/p1np1npp/5b2/2P5/PPN3PP/1BN1PPBK/1RQR4 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.032\"; c0 \"e4=10, e3=2, f3=5, Kg1=2, Rd2=3, Rf1=4\";", "2r2nk1/2q1pp1p/3p2p1/pr6/2P1PP2/1PR3PP/3Q2B1/3R2K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.033\"; c0 \"e5=10, cxb5=6, Qe2=7, Qe3=7, Re1=7\";", "2r2rk1/pp2qpp1/2nbp2p/2Np1b2/1P1Pn3/P3PN2/3BBPPP/R1RQ2K1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.034\"; c0 \"e5=10, a6=2, Nxd2=1, Rfd8=1, Rfe8=2\";", "2r3k1/4n1b1/1p1pq1p1/4p3/2r2P1P/P2NP3/1B1Q3P/4RRK1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.035\"; c0 \"e4=10, fxe5=9, Nb4=9, Qg2=9\";", "2r3k1/4Qp1p/3p2p1/3q4/b1p5/P1b3P1/R3PP1P/1R3BK1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.036\"; c0 \"e4=10\";", "2r4r/2qb1nk1/3ppp2/p1p5/P3P3/1PR3P1/3NRPK1/3Q1B2 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.037\"; c0 \"d5=10, Rh6=1, Rh7=1\";", "2rbr1k1/1p1nqp1p/4bn1P/pP2p1p1/N7/P1NRPP2/1Q2BBP1/1K5R w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.038\"; c0 \"e4=10, Bg3=2, Ka1=2\";", "2rq1rk1/6bp/p1npb3/1p1Npp1Q/8/2PBN3/PP3PPP/R3K2R b KQ - bm e4; id \"STS(v13.0) Pawn Play in the Center.039\"; c0 \"e4=10, b4=3, Bxd5=1, Kh8=2, Qd7=1\";", "2rqr2k/pp3pp1/1nb2n2/7p/3pPP2/1P1B2NP/P5P1/RQB2R1K w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.040\"; c0 \"e5=10, Ba3=3, Bb2=1, Re1=3\";", "2rrb1k1/1p3pp1/p1p4p/P5q1/2BP4/1P1RPQP1/5P2/3R1K2 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.041\"; c0 \"d5=10, Ra1=6, Rc3=6\";", "3qr1k1/1p2npb1/2ppb1pp/4p3/1PP5/R1NP2P1/2NQPPBP/6K1 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.042\"; c0 \"d5=10, f5=8, h5=2, Kh7=6, Qc7=9, Qd7=2, Rf8=2\";", "3r1k2/5p2/1p2q1p1/p2p4/P7/1P1Q3P/4nPP1/B2R3K b - - bm d4; id \"STS(v13.0) Pawn Play in the Center.043\"; c0 \"d4=10, f5=8, Nf4=8, Rd7=8\";", "3r1r2/1b2qpkp/p2p1np1/1pp5/4P3/P1N1QB2/1PP2PPP/3R1RK1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.044\"; c0 \"e5=10, h3=7, Qc1=7, Rfe1=7\";", "3r1rk1/ppqnppb1/n1p3pp/8/N2P4/3QP1P1/PP1B1PBP/R4RK1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.045\"; c0 \"e5=10, Ndb8=8, Nf6=8, Rfe8=8\";", "3r2k1/1pp1q2p/p5pb/2n1p2r/5PQ1/P1PP3P/1P5K/1BBR1R2 w - - bm d4; id \"STS(v13.0) Pawn Play in the Center.046\"; c0 \"d4=10, Ba2+=1\";", "3r2rk/1q2b2p/pNb2p2/P4Qn1/1p1p4/4PP2/1P1BB2P/2R2R1K w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.047\"; c0 \"e4=10, b3=7, Bxb4=9, exd4=7, Rc4=7\";", "3rr1k1/1p3p1p/2b1pqp1/p3N3/2PP4/4R1P1/P2Q1P1P/4R1K1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.048\"; c0 \"d5=10, a4=4, Rd1=5, Rd3=5\";", "3rr1k1/pp4bp/2p3p1/P4p2/2qPP3/B1P4P/2P3P1/R3QRK1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.049\"; c0 \"e5=10, Bc5=1, Qg3=1, Rb1=1\";", "4b3/3k1n2/2pB1p1p/1p3Pp1/1P2P1P1/8/r3BK2/3R4 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.050\"; c0 \"e5=10, Bc5+=9, Bf8+=9\";", "4r1k1/1p1r1ppb/1qpp1n1p/p7/P1PRPN2/2Q2P2/1P4PP/1B1R2K1 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.051\"; c0 \"d5=10, Qa7=6, Rdd8=6, Red8=6\";", "4r1k1/1r2ppnp/1q4p1/ppp5/3nP3/1P2QP2/P2R1BPP/2R2B1K b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.052\"; c0 \"e5=10, Rbb8=3, Rc7=3, Rd8=5\";", "4r1k1/2qn1pb1/rn1p2pp/2p5/p1b1PPP1/R1N1B2P/1PP1NQB1/R6K b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.053\"; c0 \"d5=10, Qb8=4, Ra5=3, Ra7=3\";", "4r3/2qnr1k1/4ppp1/p1p4p/p1P2P1P/3PQNP1/1P2R3/4R1K1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.054\"; c0 \"e5=10, Qb7=7, Qc6=9, Rb8=9, Rd8=4\";", "4rrk1/p4p1p/1qb3p1/2pp4/8/1P3B2/P1PQ1PPP/R3R1K1 b - - bm d4; id \"STS(v13.0) Pawn Play in the Center.055\"; c0 \"d4=10, Qb7=9, Rd8=9, Rxe1+=9\";", "5k2/4pp1p/r2p2p1/8/6P1/5P2/1R3B1P/2r2BK1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.056\"; c0 \"e5=10, f6=9, Ra8=4, Rac6=9\";", "5rk1/1ppqnr2/3p3p/1P4p1/3PPp2/5P2/P2QN2P/2R3RK w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.057\"; c0 \"d5=10\";", "5rk1/1r2bpp1/pp2qn1p/2p5/P7/2N1PPP1/1PQB2KP/2RR4 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.058\"; c0 \"e4=10, b3=1, Ne2=2\";", "5rk1/6p1/2pp4/4q1p1/1PP1PnP1/4Q2P/R7/5BK1 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.059\"; c0 \"d5=10, Kh8=5\";", "5rk1/rbqnbppp/1p2pn2/2p5/4P3/P1P2NPP/1B1N1P2/R2QRBK1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.060\"; c0 \"e5=10, Bb5=2, c4=1, Qc2=2\";", "r1b1kb1r/1p1ppppp/p2q2n1/2pN3Q/8/8/PPPP1PPP/R1B1RBK1 w kq - bm d4; id \"STS(v13.0) Pawn Play in the Center.061\"; c0 \"d4=10, b3=2, c4=3, g3=2, Ne3=1\";", "r1b1r1k1/4q1pp/1bp1pp2/np6/3PN3/3NP1PB/R1Q2P1P/3R2K1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.062\"; c0 \"e5=10, Kh8=2, Ra7=2, Rd8=2\";", "r1b1r1k1/ppq2pp1/2n1pn1p/8/2P5/PN4P1/1BP2PBP/R2Q1RK1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.063\"; c0 \"e5=10, a5=2, Rb8=2\";", "r1b1r3/pp1nq1kp/2pp2p1/5p2/1PP2P2/1Q2P1PP/P2N2B1/3R1RK1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.064\"; c0 \"e4=10, Qb2+=2, Qc3+=3, Rfe1=4\";", "r1b2rk1/1p1n1p1p/p5p1/q2p2B1/1bpP4/2N1PN1P/PPQ2PP1/2R2RK1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.065\"; c0 \"e4=10, Bf4=1, Rfe1=2\";", "r1b2rk1/1p3pb1/pq1Pp1p1/5n1p/2B2P2/1NP2Q2/PP1P2PP/R1B1K2R b KQ - bm e5; id \"STS(v13.0) Pawn Play in the Center.066\"; c0 \"e5=10, a5=7, Bd7=7, Nxd6=7, Qxd6=7\";", "r1b2rk1/p1B1bpp1/q3pn1p/3p4/8/2N3PP/PPQ1PPB1/R3R1K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.067\"; c0 \"e4=10, Be5=2, Rac1=2, Rad1=2\";", "r1b3k1/1p1n1qpp/2p1p3/3p1r2/2PP4/1PR5/2QNPPBP/5RK1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.068\"; c0 \"e4=10, b4=1, Rf3=1\";", "r1br2k1/1p3ppp/p1p5/P5q1/1bBP4/1P2P3/1BQ2PP1/R2R2K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.069\"; c0 \"e4=10, Bc3=7, Be2=7, Qe2=7\";", "r1q1nrk1/pp2ppbp/2n3p1/8/Q3P3/N5P1/PB3PBP/3RR1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.070\"; c0 \"e5=10, Bc1=8, Qb3=8, Qc2=8\";", "r1r1q1k1/1n1b2bp/p4pp1/1p6/2pNP2B/Q1P5/P1B2PPP/3RR1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.071\"; c0 \"e5=10, Bg3=5, h3=3, Qc1=4, Re2=2\";", "r1r3k1/1pp2ppp/2np1n2/1N6/p1PP4/Q3RNPq/PP3P1P/2R3K1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.072\"; c0 \"d5=10, Rce1=4, Re2=3, Ree1=2\";", "r2q1kr1/1b2np2/p2p1p1p/4p3/2N1P3/3B4/PP3PPP/1R1Q1RK1 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.073\"; c0 \"d5=10\";", "r2q1rk1/1p1n1ppp/6b1/n2B4/Ppp2NP1/4PP2/1P4KP/R1BQ1R2 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.074\"; c0 \"e4=10, Bd2=4, h4=4, Nxg6=3, Qe2=2\";", "r2q1rk1/4nbbp/p2p4/1p3p1Q/4pN2/1BP1N3/PP3PPP/R3K2R b KQ - bm d5; id \"STS(v13.0) Pawn Play in the Center.075\"; c0 \"d5=10, b4=9, Be5=7, Qe8=7\";", "r2qr1k1/1b3pb1/p2p2p1/8/2BNn1P1/2p1B3/P1P5/1NKRQR2 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.076\"; c0 \"d5=10\";", "r2r1k2/4q1p1/2b2p1p/ppP1pQ2/8/1P2PB2/5PPP/R1R3K1 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.077\"; c0 \"e4=10\";", "r2r2k1/1b2qppp/p3pn2/R7/2N5/1P1BP3/2Q2PPP/R5K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.078\"; c0 \"e4=10, f3=8, Ne5=2, Rd1=2\";", "r2r2k1/1bq2p1p/p3nnpQ/P2pp3/8/2PNN3/1P3PPP/R2R1BK1 b - - bm d4; id \"STS(v13.0) Pawn Play in the Center.079\"; c0 \"d4=10, Ne8=1, Nh5=9, Rab8=6, Rac8=9, Rd7=1\";", "r2r2k1/6bp/1P2q1p1/4pp2/p1N5/2Q5/PPR3PP/4R2K b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.080\"; c0 \"e4=10, Qc6=6, Rab8=2, Rd7=4\";", "r2r2k1/p1q3pp/1p1npp2/2p5/P1PP4/B3PP2/6PP/2RQ1RK1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.081\"; c0 \"d5=10, dxc5=8, Qb3=8, Re1=7\";", "r2r2k1/pbq2ppp/1p3n2/4p3/2PP4/PB1Q4/1B3PPP/R4RK1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.082\"; c0 \"d5=10, f3=1, Rfd1=1\";", "r2r2k1/pp2ppbp/2q3p1/2pnP3/2Q5/1P4P1/PB2PPNP/R2R2K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.083\"; c0 \"e4=10, a4=3, f4=2, Ne1=2, Rac1=8\";", "r2r2k1/ppq1p2p/1np1p1p1/2B5/P7/3P3P/1P2QPP1/R3R1K1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.084\"; c0 \"e5=10, Qc8=7, Qd7=7, Rf8=7\";", "r2r2k1/ppq2pp1/2p1pnbp/8/3P3P/1QP2P2/P3P2P/R1B2BRK w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.085\"; c0 \"e4=10, Bd2=4, Be3=4, Rg2=4\";", "r2r2k1/ppq2pp1/5nnp/1B3b2/2PPp3/P6P/1B1NQPP1/2R2RK1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.086\"; c0 \"d5=10, Ba1=1, Ba4=2, Qe3=5\";", "r2r3k/p2qppbp/1pn2np1/2p5/2P2P2/B1N1PN2/P2PQ1PP/3R1R1K w - - bm d4; id \"STS(v13.0) Pawn Play in the Center.087\"; c0 \"d4=10, d3=1\";", "r2r4/2q1bp1k/1nb1p1pp/p1ppP3/P1P2P2/1P3BPP/1N2QB2/2RR2K1 b - - bm d4; id \"STS(v13.0) Pawn Play in the Center.088\"; c0 \"d4=10, dxc4=2, Rab8=1\";", "r3kb1r/1q1n2p1/2bpp1Pp/pN3p2/1p1BP2P/P2B1P2/1PP5/2KR1Q1R b kq - bm e5; id \"STS(v13.0) Pawn Play in the Center.089\"; c0 \"e5=10\";", "r3r1k1/1p2bppp/nqp2n2/p5B1/2bPP3/P1N3P1/1P2N1BP/R1Q2RK1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.090\"; c0 \"e5=10, Bf3=7, Kh1=7, Rf5=7\";", "r3r1k1/1p2qpp1/1bp2n1p/2n1pP2/p5P1/B6P/PPPNQPB1/R2R2K1 b - - bm e4; id \"STS(v13.0) Pawn Play in the Center.091\"; c0 \"e4=10, Ba7=3, Bc7=6, Nd5=5, Qc7=5\";", "r3r1k1/4npbp/bqnpp1p1/2p3P1/1p2PP2/3PN3/1PPQNBBP/1R3RK1 b - - bm d5; id \"STS(v13.0) Pawn Play in the Center.092\"; c0 \"d5=10\";", "r3r1k1/5pp1/1qp3bp/p2pP3/8/P1Q3N1/1P3PPP/2R1R1K1 b - - bm d4; id \"STS(v13.0) Pawn Play in the Center.093\"; c0 \"d4=10\";", "r3r1k1/pp4pp/2pnqpn1/3p1b2/3P4/P1NBPN2/1PQ2PPP/2R1R1K1 w - - bm e4; id \"STS(v13.0) Pawn Play in the Center.094\"; c0 \"e4=10\";", "r4r1k/1bq3p1/pp1bpn1p/2pp4/3P3Q/1NP1B3/PP2BPPP/R4RK1 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.095\"; c0 \"e5=10, a5=5, Bc8=3, Kg8=3, Rac8=3, Rf7=2\";", "r4rk1/1p1qppbp/1n1p2p1/1PpP3n/p3P3/2NQ1N1P/1PPB1PP1/R3R1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.096\"; c0 \"e5=10, Bg5=3, Ra2=3, Ra3=2\";", "r4rk1/2p1bppp/p2p1n2/1p6/3PP3/1QN1BP1q/PP3P1P/2R1R1K1 w - - bm e5; id \"STS(v13.0) Pawn Play in the Center.097\"; c0 \"e5=10, Bf4=8, Nd5=7, Qd1=7\";", "r4rk1/3qbppp/p1np1n2/1pp4b/3PP3/PB2BN1P/1P1N1PP1/RQ2R1K1 w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.098\"; c0 \"d5=10, Bc2=1\";", "r4rk1/pbp5/1p1p1n1p/5Bp1/P1PP4/4q3/1P1N2PP/2RQ1R1K w - - bm d5; id \"STS(v13.0) Pawn Play in the Center.099\"; c0 \"d5=10, Bb1=4, Nf3=1\";", "rq3k2/1p3bp1/2p1pp1p/2P5/1P2PPP1/4Q2P/6BK/3R4 b - - bm e5; id \"STS(v13.0) Pawn Play in the Center.100\"; c0 \"e5=10, Kg8=8, Qa7=8, Qc7=8\";", "1k5r/1p1b4/4pp1r/3p4/q4PQ1/3B1R1P/2P1R1PK/8 w - - bm Qg7; id \"STS(v14.0) 7th Rank.001\"; c0 \"Qg7=10, Qg3=3, Re1=3, Ree3=2, Ref2=2\";", "1n1r1rk1/4bpp1/p2p3p/1q1Qp3/1P2P3/P3BN1P/5PP1/2R1R1K1 w - - bm Rc7; id \"STS(v14.0) 7th Rank.002\"; c0 \"Rc7=10, Nd2=6, Qxb5=8, Red1=6\";", "1n2r3/ppb2kp1/5p1p/2p2N1P/6P1/2B5/PPP2P2/2KR4 b - g3 bm Re2; id \"STS(v14.0) 7th Rank.003\"; c0 \"Re2=10, Bb6=7, Bf4+=7, Re4=7\";", "1r1n4/5pk1/Qp1r1qp1/3B3p/1R2P2P/6P1/5P2/1R4K1 w - - bm Qa7; id \"STS(v14.0) 7th Rank.004\"; c0 \"Qa7=10\";", "1r1q2k1/3b1pb1/p2p2p1/3Np3/4P1P1/1P1Q1P2/KP1B4/2R5 w - - bm Rc7; id \"STS(v14.0) 7th Rank.005\"; c0 \"Rc7=10, g5=5, Rc2=7, Rc3=5\";", "1r1r2k1/4pp2/1PR3p1/p2P1n1p/1p1q1Q2/5P1P/2B1RPPK/8 w - - bm Qc7; id \"STS(v14.0) 7th Rank.006\"; c0 \"Qc7=10, Qc1=1, Re4=1\";", "1r1r4/5ppk/4pb2/7p/PN3P2/1Rp3P1/2P3P1/4RK2 b - - bm Rd2; id \"STS(v14.0) 7th Rank.007\"; c0 \"Rd2=10, Be7=5, h4=6, Rd4=7\";", "1r1r4/6bk/p1Rp2p1/P6p/1q1pPB1P/5PP1/Q4K2/2R5 w - - bm Rc7; id \"STS(v14.0) 7th Rank.008\"; c0 \"Rc7=10, Bd2=7, Kg2=6, R1c4=6\";", "1r2r1k1/1b1n1ppp/1p2p3/1N1pP3/Pb3P2/4BB2/1PR3PP/R6K w - - bm Rc7; id \"STS(v14.0) 7th Rank.009\"; c0 \"Rc7=10, Bd2=2, Kg1=1, Nd6=3, Rac1=1\";", "1r2r2k/B1p2p1p/p2p2p1/4b3/n1P1P1P1/5B2/P4P1P/1R3RK1 b - - bm Rb2; id \"STS(v14.0) 7th Rank.010\"; c0 \"Rb2=10, Ra8=1, Rbc8=1, Rxb1=6\";", "1r3rk1/qn2n2p/3p1p2/pp1Pp1p1/1N2P3/QP5P/P1R2PP1/2R2NK1 w - - bm Rc7; id \"STS(v14.0) 7th Rank.011\"; c0 \"Rc7=10, Nc6=3, Ne3=2, Ng3=3, Rd1=6\";", "1r4k1/3b2pp/4p3/2bpq3/3N4/2PB4/P4QPP/5RK1 w - - bm Qf7+; id \"STS(v14.0) 7th Rank.012\"; c0 \"Qf7+=10, Kh1=8, Qc2=9, Re1=9\";", "1r4k1/6b1/2r1n2p/2pRp1p1/2P3P1/4BK2/R2N1P1P/8 w - - bm Ra7; id \"STS(v14.0) 7th Rank.013\"; c0 \"Ra7=10, Kg3=8, Ne4=3, Ra5=7, Rd7=8\";", "1r4k1/pp3p2/3p1B2/3P3p/2R5/7P/P1P3P1/2b4K w - - bm Rc7; id \"STS(v14.0) 7th Rank.014\"; c0 \"Rc7=10, Be7=8, g3=8, Kg1=4, Kh2=7\";", "1r4k1/qr1p2p1/2n1p2p/2b1P2P/2BpPB2/p2P4/3Q1PPK/R1R5 b - - bm Rb2; id \"STS(v14.0) 7th Rank.015\"; c0 \"Rb2=10, Bb4=5, Kh7=4, Rb6=4\";", "1r6/5pk1/Qp1rnqp1/3B3p/1R2P2P/6P1/5PK1/1R6 w - - bm Qa7; id \"STS(v14.0) 7th Rank.016\"; c0 \"Qa7=10, Qc4=6, Qe2=6, R4b2=6\";", "1rb1k2r/2qpbppp/p3pn2/1p2n3/3QP3/PNN1BP2/1PP3PP/2KR1B1R w k - bm Qa7; id \"STS(v14.0) 7th Rank.017\"; c0 \"Qa7=10, Be2=3, h4=3, Kb1=3, Na5=3\";", "1rbqr1k1/3n1pbp/p2Q2p1/2pN4/1pP1n3/5NPP/PP3PB1/1RB1R1K1 w - - bm Qc7; id \"STS(v14.0) 7th Rank.018\"; c0 \"Qc7=10, Qc6=2, Qf4=3\";", "2b4r/5kpp/p2q4/1p1p1P2/2n3P1/8/PPP2Q1P/1K1RR3 w - - bm Qa7+; id \"STS(v14.0) 7th Rank.019\"; c0 \"Qa7+=10, b3=3, g5=2, Qd4=2, Rd3=1\";", "2k5/p1pb1p2/1p4p1/2p1P3/2P2KPb/1P2N2r/PB1R1P2/8 b - - bm Rh2; id \"STS(v14.0) 7th Rank.020\"; c0 \"Rh2=10, a5=4, g5+=6, Rh1=4\";", "2qb1rk1/1brn1pp1/3p3p/1B1Pp3/4P1P1/R3BN1P/4QP1K/1R6 w - - bm Ra7; id \"STS(v14.0) 7th Rank.021\"; c0 \"Ra7=10, Bd3=7, Bxd7=9, Nd2=9, Qb2=7\";", "2r1kb1r/1b1p1ppp/p3pn2/qp6/3QPP2/2N1BB2/PPPR2PP/2K4R w k - bm Qa7; id \"STS(v14.0) 7th Rank.022\"; c0 \"Qa7=10, e5=2, Kb1=1, Rd3=3, Re1=3\";", "2r1N3/pp3p1k/2p3p1/2n5/7P/5KP1/PP3P2/4R3 w - - bm Re7; id \"STS(v14.0) 7th Rank.023\"; c0 \"Re7=10, b4=2, Nd6=2, Re5=2\";", "2r2k2/5p2/R1b2p2/1pP1p2p/1Pp1P2P/2K2P2/5BP1/8 w - - bm Ra7; id \"STS(v14.0) 7th Rank.024\"; c0 \"Ra7=10, Be3=5, Bg1=3, Kd2=3\";", "2r2r1k/3n3p/3q2p1/4p1Q1/Pp1bp1NN/1P2B2P/4nPP1/1R1R3K b - - bm Rc2; id \"STS(v14.0) 7th Rank.025\"; c0 \"Rc2=10, Qe6=3\";", "2r2rk1/4pp2/Qp3qp1/3B3p/3nP3/8/P4PPP/1R1R2K1 b - - bm Rc2; id \"STS(v14.0) 7th Rank.026\"; c0 \"Rc2=10, e6=3, h4=4, Kg7=3\";", "2r2rk1/p4ppp/bp2p3/3pB3/1b1PP1P1/qP2Q3/P4PBP/R1R3K1 b - - bm Qb2; id \"STS(v14.0) 7th Rank.027\"; c0 \"Qb2=10, f6=6, Rxc1+=2\";", "2r3k1/1qpbbppp/3p4/Qp1P4/3p4/1B1P4/1PPB1PPP/R5K1 w - - bm Qa7; id \"STS(v14.0) 7th Rank.028\"; c0 \"Qa7=10, f3=6, Qa6=8, Ra2=8\";", "2r3k1/3q2p1/3b1p1p/1p1PpP2/1Pp1B3/2P4P/Q5P1/R5K1 w - - bm Qa7; id \"STS(v14.0) 7th Rank.029\"; c0 \"Qa7=10, Kf2=6, Kh2=6, Qa6=7\";", "2r3k1/4bqp1/p3p3/1p5p/2n2P1P/P2Q1N2/1PP5/1KBR4 w - - bm Qd7; id \"STS(v14.0) 7th Rank.030\"; c0 \"Qd7=10, Ng5=4, Qe2=4, Re1=4, Rg1=4\";", "2r3k1/4np2/p3p1p1/1q1r1n1p/1p1P4/PN5R/1P2NPPP/3RQ1K1 b - - bm Rc2; id \"STS(v14.0) 7th Rank.031\"; c0 \"Rc2=10, bxa3=6, Rd6=7, Rdd8=8\";", "2r3k1/5pp1/p3n3/4p2p/1QP1P3/1PR2P2/P6q/1KB5 w - - bm Qb7; id \"STS(v14.0) 7th Rank.032\"; c0 \"Qb7=10, Qa3=8, Qa4=8, Qa5=8, Qd6=8, Rd3=8\";", "2r3k1/p1q1np2/2P1pp1p/P7/8/3Q1BPP/5PK1/2R5 w - - bm Qd7; id \"STS(v14.0) 7th Rank.033\"; c0 \"Qd7=10, Qa6=5, Qd2=5, Qd4=7\";", "3q1rk1/5b2/5Rp1/p1p1p1P1/2P1PP2/1P4Qp/4B2K/8 b - - bm Qd2; id \"STS(v14.0) 7th Rank.034\"; c0 \"Qd2=10, a4=8, Be8=8, exf4=7\";", "3q1rk1/5ppp/pp1p4/6b1/2rNQ3/6P1/PP2PP1P/R2R2K1 w - - bm Qb7; id \"STS(v14.0) 7th Rank.035\"; c0 \"Qb7=10, b3=4, e3=3, Qd5=4\";", "3q4/5ppk/2p1n2p/2n1pN1P/4P3/Q1P2PP1/6BK/8 w - - bm Qa7; id \"STS(v14.0) 7th Rank.036\"; c0 \"Qa7=10, Kg1=1, Kh1=1, Nh4=1, Qb2=1, Qb4=1\";", "3qr3/2p1kp2/1p4pQ/1P1P3p/7P/6P1/5P2/3R2K1 w - - bm Qg7; id \"STS(v14.0) 7th Rank.037\"; c0 \"Qg7=10, d6+=7, Kg2=3, Qd2=2, Rd4=2\";", "3qr3/5pkp/p1npb1p1/3N4/2PpPP2/6P1/PQ4BP/1R5K w - - bm Qb7; id \"STS(v14.0) 7th Rank.038\"; c0 \"Qb7=10, Qa3=2, Rf1=1\";", "3r1k2/1p3p1Q/p1br1p2/2p1pB2/2P1PP2/2q5/P5PP/1R2R1K1 b - - bm Rd2; id \"STS(v14.0) 7th Rank.039\"; c0 \"Rd2=10, Ke7=2, Qxc4=2, Rd3=2\";", "3r2k1/2R2pp1/p4n1p/1p3P2/1P6/5B1P/P5P1/6K1 b - - bm Rd2; id \"STS(v14.0) 7th Rank.040\"; c0 \"Rd2=10, Nd5=6, Rd3=8, Rd4=7\";", "3r2k1/6pp/1pq5/p2pR3/3Q4/P5P1/1P3P1P/6K1 w - - bm Re7; id \"STS(v14.0) 7th Rank.041\"; c0 \"Re7=10, b4=6, h4=4, Kg2=3, Re3=5\";", "3r2k1/p2n1p1p/2p1p1p1/P7/3P4/P2B4/5PPP/1R4K1 w - - bm Rb7; id \"STS(v14.0) 7th Rank.042\"; c0 \"Rb7=10, Bc2=8, Be2=8, Bf1=8, Kf1=8\";", "3r2k1/p3pp1p/6p1/2p5/2P1n3/RP2P1P1/4KP1P/B7 b - - bm Rd2+; id \"STS(v14.0) 7th Rank.043\"; c0 \"Rd2+=10, f6=3, Nd2=2, Rd7=3\";", "3r2k1/pp3bbp/3q1p2/2p5/5pQ1/1P3N2/P3R1PP/4R2K w - - bm Re7; id \"STS(v14.0) 7th Rank.044\"; c0 \"Re7=10\";", "3r2r1/3kp1P1/2p5/1q1pP3/1p6/1Pb2Q2/PN4R1/1K1R4 w - - bm Qf7; id \"STS(v14.0) 7th Rank.045\"; c0 \"Qf7=10, Nd3=8, Qe3=4, Rc1=5\";", "3r3k/p4p1p/b4Prp/1p2R3/1P1p4/6PP/P4PB1/3R2K1 w - - bm Re7; id \"STS(v14.0) 7th Rank.046\"; c0 \"Re7=10, Rd2=4, Re4=6, Rf5=7\";", "3r4/3r2bk/1p4pp/pN2n3/P6P/4Q1P1/1P2B1K1/8 b - h3 bm Rd2; id \"STS(v14.0) 7th Rank.047\"; c0 \"Rd2=10, h5=7\";", "3r4/3rq1k1/1R1p2pp/1Rp1p3/P3N3/2P1nP2/1Q4PP/6K1 w - - bm Rb7; id \"STS(v14.0) 7th Rank.048\"; c0 \"Rb7=10, Qa2=4, Qe2=5, Rc6=4\";", "3rk3/1p3pQp/p4R2/3p4/2P5/1P2q1P1/P1K4P/8 b - - bm Qe2+; id \"STS(v14.0) 7th Rank.049\"; c0 \"Qe2+=10, Kd7=7, Qe4+=7, Qe7=7\";", "3rkb1r/pp2pppp/1n2q3/8/7Q/2P5/PP3PPP/RNB2RK1 b k - bm Qe2; id \"STS(v14.0) 7th Rank.050\"; c0 \"Qe2=10, Qc6=1, Qd5=1, Qf5=1\";", "4b3/p2nP1k1/1r2R1p1/q1p5/2Br2P1/1P2QP2/P1P5/4R1K1 b - - bm Qd2; id \"STS(v14.0) 7th Rank.051\"; c0 \"Qd2=10, Rb8=6, Rd2=5, Rdd6=6, Rxe6=6\";", "4n3/7k/2Q3pb/1ppPp3/2q1P3/r5PP/1RB2BK1/8 b - - bm Qe2; id \"STS(v14.0) 7th Rank.052\"; c0 \"Qe2=10\";", "4q1k1/2p2pp1/p6p/Pr1P4/2p1P3/2P3P1/r6P/3QRR1K b - - bm Rbb2; id \"STS(v14.0) 7th Rank.053\"; c0 \"Rbb2=10, c6=6, Qe7=4, Rbxa5=6\";", "4r1k1/1p3p2/2p3p1/8/6P1/3r2P1/n5BP/N4RBK b - - bm Re2; id \"STS(v14.0) 7th Rank.054\"; c0 \"Re2=10\";", "4r1k1/1p6/pB3p2/P1R2Pp1/1P2b1r1/4P3/2N4b/2KR4 b - - bm Rg2; id \"STS(v14.0) 7th Rank.055\"; c0 \"Rg2=10, Bc6=5, Be5=7, Bf3=5\";", "4rk2/4p2p/3p1pp1/1p1P4/1Pq2P1P/P2RQ3/2r3P1/4R1K1 b - - bm Qa2; id \"STS(v14.0) 7th Rank.056\"; c0 \"Qa2=10, Kg7=3, Kg8=3, Qc8=6, Rb2=4\";", "5k2/1p1b2p1/pq2p1Q1/3p2P1/8/8/PPP1N2P/1K6 b - - bm Qf2; id \"STS(v14.0) 7th Rank.057\"; c0 \"Qf2=10, Kg8=7, Qd6=7, Qe3=5\";", "5k2/1p1r1pp1/6b1/q1r1pNPp/1Nn1P2P/p1P2Q2/P4P2/K1RR4 b - - bm Rd2; id \"STS(v14.0) 7th Rank.058\"; c0 \"Rd2=10, Nd2=2, Qc7=1, Rcc7=4, Rxd1=3\";", "5k2/5p2/3p2p1/p3q1P1/6b1/P1NR4/1PP2r2/1KQ5 b - - bm Qh2; id \"STS(v14.0) 7th Rank.059\"; c0 \"Qh2=10, Be6=4, Bf5=1, Qf5=3, Rh2=1\";", "5r1k/p2nq1pp/8/P7/1b1Pp3/1B3p1P/2Q2PP1/2B2RK1 w - - bm Qc7; id \"STS(v14.0) 7th Rank.060\"; c0 \"Qc7=10\";", "5r2/6k1/3p3p/1p1Qbbp1/1PP5/6NP/1q5P/4RB1K w - - bm Qb7+; id \"STS(v14.0) 7th Rank.061\"; c0 \"Qb7+=10, Bg2=8, c5=8, cxb5=8\";", "5rk1/5bpp/8/r2p1P2/3Bp1P1/1BR1P1K1/1n5P/2R5 w - - bm Rc7; id \"STS(v14.0) 7th Rank.062\"; c0 \"Rc7=10, Rc5=5, Rc6=4, Rc8=4\";", "6k1/1b2bp2/p3p2p/4P1p1/1pr5/4BP1P/PP2N1P1/3R2K1 b - - bm Rc2; id \"STS(v14.0) 7th Rank.063\"; c0 \"Rc2=10, Bc5=3, Bd5=4, Kf8=2, Rc7=4\";", "6k1/1p3pb1/p2qp1np/7p/Q7/4N1BP/PPP2PP1/6K1 b - - bm Qd2; id \"STS(v14.0) 7th Rank.064\"; c0 \"Qd2=10, Be5=2, Qb6=4, Qd8=2\";", "6k1/2nr2p1/2R2p1p/R2n3P/p2P4/r4NN1/5PP1/6K1 w - - bm Ra7; id \"STS(v14.0) 7th Rank.065\"; c0 \"Ra7=10, Nf5=3, Rcc5=1\";", "6k1/5p1p/4pPpP/3p4/qpnB1P2/rN4P1/2B3K1/3Q4 b - - bm Ra2; id \"STS(v14.0) 7th Rank.066\"; c0 \"Ra2=10\";", "7k/4p1q1/3pnbr1/8/1N5p/1NPP1P2/PP6/K1R3BR b - - bm Rg2; id \"STS(v14.0) 7th Rank.067\"; c0 \"Rg2=10, Kg8=5, Nf4=7, Qh6=6, Qh7=6\";", "7k/rr4p1/4qnQp/8/2P1p3/p3N2P/R4PP1/5RK1 b - - bm Rb2; id \"STS(v14.0) 7th Rank.068\"; c0 \"Rb2=10, Qe7=1\";", "7r/4k1p1/p2pP1p1/n2P4/1p2N2r/1P3P2/P2R2K1/4R3 b - - bm Rh2+; id \"STS(v14.0) 7th Rank.069\"; c0 \"Rh2+=10, Nb7=7, Nxb3=7, Rc8=7\";", "7r/8/5p1r/P3p1k1/1p1bP1p1/p2N4/P1PR2P1/1K3R2 b - - bm Rh2; id \"STS(v14.0) 7th Rank.070\"; c0 \"Rh2=10, Kg6=6, Rh7=6, Ra8=7, Rh1=9\";", "8/5nkq/1rNp1pp1/2pPp1p1/1n2P1P1/1PN2P2/6P1/R2Q2K1 w - - bm Ra7; id \"STS(v14.0) 7th Rank.071\"; c0 \"Ra7=10, Na4=2, Nb1=2, Qd2=2, Ra8=2\";", "8/5pk1/3p2p1/p1q3Pn/5rb1/1BN5/PPPQ4/1K2R3 b - - bm Rf2; id \"STS(v14.0) 7th Rank.072\"; c0 \"Rf2=10, Bf3=8, Bf5=8, Qxg5=8\";", "qr4k1/6b1/r6p/P2p1pp1/1B1P4/Q2NP1P1/5P1P/2R3K1 w - - bm Rc7; id \"STS(v14.0) 7th Rank.073\"; c0 \"Rc7=10\";", "r1b1k2r/pp2pp1p/1qnp2p1/8/2P1P1n1/2Q2P2/PPN3PP/1RB1KB1R b Kkq - bm Qf2+; id \"STS(v14.0) 7th Rank.074\"; c0 \"Qf2+=10, Nce5=8, Nf6=6, Nge5=8\";", "r1b1k2r/ppp2p1p/2n2p2/1B1q4/8/6Q1/PPP2PPP/R3K1NR w KQkq - bm Qg7; id \"STS(v14.0) 7th Rank.075\"; c0 \"Qg7=10, Bxc6+=4, c4=3, Qe3+=4\";", "r1b1k2r/ppp2p1p/2q2p2/8/8/6Q1/PPP2PPP/R3K1NR w KQkq - bm Qg7; id \"STS(v14.0) 7th Rank.076\"; c0 \"Qg7=10, Ne2=3, O-O-O=2, Qe3+=3\";", "r1b1qrk1/pp2bppp/4pn2/4Q1B1/8/2N5/PPP2PPP/2KR1B1R w - - bm Qc7; id \"STS(v14.0) 7th Rank.077\"; c0 \"Qc7=10, Be2=4, h4=3, Qg3=4\";", "r1b2rk1/1p2q1b1/1n4p1/pP1p4/3Pp3/6BN/P2QBPP1/2R1K2R w K - bm Rc7; id \"STS(v14.0) 7th Rank.078\"; c0 \"Rc7=10, Bc7=3, Be5=3\";", "r1b2rk1/pp2ppbp/2n3p1/2pq4/8/P2P1NP1/1P2PPBP/1RBQ1RK1 b - - bm Qa2; id \"STS(v14.0) 7th Rank.079\"; c0 \"Qa2=10, b6=8, Bd7=6, Qh5=7\";", "r1b5/pp2b1kp/3rpqp1/2Q2p2/3N4/1B2P1P1/PP3P1P/2RR2K1 w - - bm Qc7; id \"STS(v14.0) 7th Rank.080\"; c0 \"Qc7=10, Qc2=2, Qc3=2, Qc4=2\";", "r1br3k/ppp3bp/2n3p1/4ppN1/2P5/1P4P1/PB2PPBP/R4RK1 b - - bm Rd2; id \"STS(v14.0) 7th Rank.081\"; c0 \"Rd2=10, Kg8=8, Rd7=9, Re8=6, Rf8=7\";", "r2q1rk1/4bppp/3pb3/2n1pP2/1p2P1PP/1P3Q2/1BP1N1B1/2KR3R b - - bm Ra2; id \"STS(v14.0) 7th Rank.082\"; c0 \"Ra2=10\";", "r2q1rk1/pp3pp1/2p2n1p/8/2B5/4PQ2/PP3PPP/2R2RK1 b - - bm Qd2; id \"STS(v14.0) 7th Rank.083\"; c0 \"Qd2=10, g6=1, Qb6=1, Qc7=1, Qe7=1\";", "r3r1k1/3b2pp/2pP1q2/ppP2pp1/5N2/8/PP1Q1PPP/3RR1K1 w - - bm Re7; id \"STS(v14.0) 7th Rank.084\"; c0 \"Re7=10, Nd3=5, Nh5=2, Rxe8+=3\";", "r4b1r/p4ppp/3kp3/1R6/8/2P2P2/P4P1P/2B1K2R w K - bm Rb7; id \"STS(v14.0) 7th Rank.085\"; c0 \"Rb7=10, a4=1\";", "r4r1k/4bpp1/p2p1nbp/q1p5/2PnPPB1/P1NPB3/1R3N1P/3Q1RK1 w - - bm Rb7; id \"STS(v14.0) 7th Rank.086\"; c0 \"Rb7=10, Bd2=6, Bxd4=7, Nd5=8\";", "r4rk1/1p5p/p3pp2/2b5/P7/2N5/1P3PPP/R2R2K1 w - - bm Rd7; id \"STS(v14.0) 7th Rank.087\"; c0 \"Rd7=10, Ne4=5, Rac1=1\";", "r4rk1/p1p2pp1/2pp1q1p/4p3/4P1b1/2PP1N2/P1P2PPP/1R1Q1RK1 w - - bm Rb7; id \"STS(v14.0) 7th Rank.088\"; c0 \"Rb7=10, a4=4, c4=3, h3=3, Rb3=3\";", "r4rk1/pp2bppp/2n3b1/3R4/8/1P2BN1P/1P2BPP1/R5K1 w - - bm Rd7; id \"STS(v14.0) 7th Rank.089\"; c0 \"Rd7=10, Nd4=2, Ne5=1, Rb5=1\";", "r4rk1/pp2n2p/4P1p1/2Qp2q1/1P6/5R2/P5PP/4RBK1 w - - bm Rf7; id \"STS(v14.0) 7th Rank.090\"; c0 \"Rf7=10, Qe3=1\";", "r4rk1/pp3ppp/2n1p3/4Pb2/2N5/3q1N2/PP3PPP/R1QR2K1 b - - bm Qc2; id \"STS(v14.0) 7th Rank.091\"; c0 \"Qc2=10, Nxe5=9, Qe2=6, Qe4=6\";", "r4rk1/ppp1bppp/2np4/3Q1q2/2P5/2P2N2/PP3PPP/R1B1R1K1 b - - bm Qc2; id \"STS(v14.0) 7th Rank.092\"; c0 \"Qc2=10, Qd7=3, Qg4=3, Qg6=3\";", "r5k1/1p2bppp/pB6/3rn3/4p3/1N2P2P/PP3PP1/2R2RK1 w - - bm Rc7; id \"STS(v14.0) 7th Rank.093\"; c0 \"Rc7=10\";", "r5k1/4bpp1/7p/2Pp4/3Bp3/r2bPP1P/3N2P1/2R1K1R1 b - - bm Ra2; id \"STS(v14.0) 7th Rank.094\"; c0 \"Ra2=10, Bd8=7, Bh4+=7, R3a5=6\";", "r5k1/5pp1/p2p1n1p/1q1Pp3/2R1P3/3Q1N1P/P4PPK/8 b - - bm Qb2; id \"STS(v14.0) 7th Rank.095\"; c0 \"Qb2=10, Kh7=6, Ne8=6, Rb8=5, Rd8=6\";", "r7/4bpk1/p5p1/1p1RP2p/8/2r1B1PP/P4P2/3R2K1 w - - bm Rd7; id \"STS(v14.0) 7th Rank.096\"; c0 \"Rd7=10\";", "rn1q1rk1/pb1nbppp/1p2p3/3pN3/3P4/6P1/PPQBPPBP/RNR3K1 w - - bm Qc7; id \"STS(v14.0) 7th Rank.097\"; c0 \"Qc7=10, Nd3=2, Nf3=2, Nxd7=2\";", "rn1r2k1/pb2ppbp/1p4p1/8/3PP3/3B1N2/P2B1PPP/2R1K2R w K - bm Rc7; id \"STS(v14.0) 7th Rank.098\"; c0 \"Rc7=10, Bb1=6, Bg5=6, Ke2=1\";", "rnb2k2/1p3ppp/4p3/1p6/4Q3/1Bq5/P3KPPP/R6R b - - bm Qb2+; id \"STS(v14.0) 7th Rank.099\"; c0 \"Qb2+=10, f5=8, Na6=8, Nc6=8, Nd7=8\";", "Rr6/5kp1/1qQb1p1p/1p1PpP2/1Pp1B3/2P4P/6P1/5K2 w - - bm Qd7+; id \"STS(v14.0) 7th Rank.100\"; c0 \"Qd7+=10, Qxb6=4, Ra1=3, Ra2=2\";", NULL }; SjaakII/include/timer.h000644 000765 000024 00000004177 12452210627 016015 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TIMER_H #define TIMER_H #ifdef __cplusplus extern "C" { #endif #include "bool.h" uint64_t get_timer(void); typedef struct chess_clock_t { /* various things having to do with time management */ int time_left; /* Total time left on the clock, in msec */ int time_inc; /* Time increment per move, in msec */ int time_per_move; /* Time per move, in msec */ int extra_time; /* Extra time allocated for this move */ uint64_t start_time; /* Timer value when the search started */ int movestogo; /* Number of moves until the next cycle */ int movestotc; /* Number of moves per cycle */ int root_moves_played; /* Total number of moves played so far in the game */ size_t max_nodes; /* Maximum number of nodes to search */ size_t nodes_searched; /* Number of nodes currently searched */ bool pondering; /* true: not our move, ignore clock but mind keyboard */ bool (*check_clock)(const struct chess_clock_t *clock); } chess_clock_t; void start_clock(chess_clock_t *clock); int peek_timer(const chess_clock_t *clock); int get_chess_clock_time_for_move(const chess_clock_t *clock); void set_ponder_timer(chess_clock_t *clock); void set_infinite_time(chess_clock_t *clock); void set_time_per_move(chess_clock_t *clock, int msec); void set_time_for_game(chess_clock_t *clock); #ifdef __cplusplus } #endif #endif SjaakII/include/variants.h000644 000765 000024 00000322271 12502323505 016516 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VARIANTS_H #define VARIANTS_H #include typedef game_t *(*new_variant_game_t)(const char *shortname); game_t *create_standard_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); game->name = strdup("Chess"); game->finalise_variant(); return game; } game_t *create_seirawan_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fh = fb | fn; move_flag_t fe = fr | fn; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fh, fh, 0, pz, "", "Hawk", "H,h", "H", 825); game->add_piece_type(fe, fe, 0, pz, "", "Elephant","E,e","E", 875); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QHERBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[HEhe] w KGFDCBQkgfdcbq - 0 1"); game->name = strdup("Seirawan"); game->add_rule(RF_GATE_DROPS); game->finalise_variant(); return game; } game_t *create_crazyhouse_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "Q~R~B~N~", "Pawn", "P,p", " ", 100); game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N~,n~", "N~", 375); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B~,b~", "B~", 375); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R~,r~", "R~", 550); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q~,q~", "Q~", 1025); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR [-] w KQkq - 0 1"); game->name = strdup("Crazyhouse"); game->add_rule(RF_ALLOW_DROPS | RF_KEEP_CAPTURE); game->finalise_variant(); /* Pawns may not be dropped on the first or last ranks */ for (int n = 0; npt.num_piece_types; n++) { game->pt.drop_zone[WHITE][n] &= game->pt.drop_zone[BLACK][n]; game->pt.drop_zone[BLACK][n] &= game->pt.drop_zone[WHITE][n]; } return game; } game_t *create_chessgi_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR [-] w KQkq - 0 1"); game->xb_setup = strdup("(PNBRQKpnbrqk) 8x8+6_crazyhouse"); game->name = strdup("Chessgi"); game->add_rule(RF_ALLOW_DROPS | RF_KEEP_CAPTURE); game->finalise_variant(); return game; } game_t *create_twilight_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR [-] w KQkq - 0 1"); game->name = strdup("Twilight Chess"); game->add_rule(RF_ALLOW_DROPS | RF_ALLOW_PICKUP); game->finalise_variant(); return game; } game_t *create_shatranj_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("leap (2,2)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 400); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 100); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 800); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 200); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "Q", "Pawn", "P,p", " ", 100); /* Stale mate is a loss */ game->stale_score = -LEGALWIN; /* A bare king is a loss (except if we can bare the enemy king on the next move, but the search takes care * of that). */ game->add_rule(RF_USE_BARERULE); game->bare_king_score = -LEGALWIN; game->start_fen = strdup("rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w 0 1"); game->name = strdup("Shatranj"); game->finalise_variant(); return game; } game_t *create_courier_game(const char *) { int files = 12; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(12, 8); move_flag_t fe = game->movegen.define_piece_move("leap (2,2)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,0)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 400); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 500); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 800); game->add_piece_type(ff, ff, 0, pz, "", "Ferz", "F,f", "F", 200); game->add_piece_type(fe, fe, 0, pz, "", "Elephant", "E,e", "E", 250); game->add_piece_type(fw, fw, 0, pz, "", "Wazir", "W,w", "W", 225); game->add_piece_type(fk, fk, 0, pz, "", "Man", "M,m", "M", 300); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "F", "Pawn", "P,p", " ", 100); /* Set the FEN string for the starting position */ game->start_fen = strdup("rnebmk1wbenr/1ppppp1pppp1/6f5/p5p4p/P5P4P/6F5/1PPPPP1PPPP1/RNEBMK1WBENR w - -"); game->name = strdup("Courier chess"); game->finalise_variant(); return game; } game_t *create_berolina_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step NE, NW"); move_flag_t fc = game->movegen.define_piece_move("step N"); move_flag_t f2 = game->movegen.define_piece_move("step 2NE, 2NW"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); game->name = strdup("Berolina Chess"); game->finalise_variant(); return game; } game_t *create_chancellor_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fn | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Chancellor", "C,c", "C", 875); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "CRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbckbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBCKBNR w KQkq - 0 1"); game->xb_setup = strdup("(PNBR............CKpnbr............ck) 8x8+0_fairy"); game->name = strdup("Chancellor Chess"); game->finalise_variant(); return game; } game_t *create_amazon_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fn | fr | fb; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Amazon", "A,a", "A",1200); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "ARBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbakbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBAKBNR w KQkq - 0 1"); game->xb_setup = strdup("(PNBR..............AKpnbr..............ak) 8x8+0_fairy"); game->name = strdup("Amazon Chess"); game->finalise_variant(); return game; } game_t *create_knightmate_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fk, fk, 0, pz, "", "Man", "M,m", "M", 300); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 450); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fn, fn, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBM", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rmbqkbmr/pppppppp/8/8/8/8/PPPPPPPP/RMBQKBMR w KQkq - 0 1"); game->name = strdup("Knightmate"); game->finalise_variant(); return game; } game_t *create_shatar_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fq = ff | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; uint32_t mf = PF_NOMATE | PF_SHAK; uint32_t sf = PF_SHAK; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, mf, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, sf, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, sf, pz, "", "Berse", "J,j", "J", 725); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "J", "Pawn", "P,p", " ", 100); game->add_rule(RF_USE_SHAKMATE); game->start_fen = strdup("rnbjkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBJKBNR w - - 0 1"); //game->start_fen = strdup("rnbjkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBJKBNR w - - 0 1"); game->xb_setup = strdup("(PNBR..........J......Kpnbr..........j......k) 8x8+0_fairy"); game->name = strdup("Shatar"); game->finalise_variant(); return game; } game_t *create_spartan_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); move_flag_t fw2 = game->movegen.define_piece_move("step 2N"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fw = fb | fn; move_flag_t fg = fr | ff; move_flag_t flm = game->movegen.define_piece_move("aleap (-1,0)|(1,0)|(1,1)|(-1,1)|(1,-1)|(-1,-1)|(2,2)|(-2,2)|(2,-2)|(-2,-2)"); move_flag_t flc = game->movegen.define_piece_move("leap (1,1)|(2,2)"); move_flag_t fc = game->movegen.define_piece_move("leap (1,0)|(2,0)"); move_flag_t fbh = game->movegen.define_piece_move("step NE,NW"); move_flag_t fbc = game->movegen.define_piece_move("step N"); move_flag_t fb2 = game->movegen.define_piece_move("leap (2,2)") | fbh; uint32_t kf = PF_ROYAL; bitboard_t rank2 = bitboard_t::board_rank[1]; bitboard_t rank7 = bitboard_t::board_rank[6]; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type( fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 475); game->add_piece_type( fg, fg, 0, pz, "", "General", "G,g", "G", 725); game->add_piece_type( fw, fw, 0, pz, "", "Warlord", "W,w", "W", 825); game->add_piece_type(flm, flc, 0, pz, "", "Lieutenant", "L,l", "L", 300); game->add_piece_type( fc, fc, 0, pz, "", "Captain", "C,c", "C", 300); game->add_piece_type(fwp, fwc, 0, pp, "QRBN", "Pawn", "P,p", " ", 100); game->add_piece_type(fbh, fbc, 0, pp, "KGWLC","Hoplite", "H,h", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", rank2, fw2); game->add_special_move("h", rank7, fb2); /* Spartans can have two kings */ game->set_maximum_number_of_kings(BLACK, 2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->start_fen = strdup("lgkcckwl/hhhhhhhh/8/8/8/8/PPPPPPPP/RNBQKBNR w KQ -"); game->name = strdup("Spartan chess"); game->add_rule(RF_KING_DUPLECHECK); game->finalise_variant(); return game; } game_t *create_super_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fe = fn | fr; move_flag_t fs = fb | fn; move_flag_t fa = fb | fr | fn; move_flag_t fv = game->movegen.define_piece_move("leap (1,0)|(1,1)|(1,2)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fe, fe, 0, pz, "", "Empress","E,e", "E", 900); game->add_piece_type(fs, fs, 0, pz, "", "Princess","S,s","S", 875); game->add_piece_type(fa, fa, 0, pz, "", "Amazon", "A,a", "A",1225); game->add_piece_type(fv, fv, 0, pz, "", "Veteran","V,v", "V", 750); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBNAESV", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->set_maximum_number_of_pieces("Q", WHITE, 1); game->set_maximum_number_of_pieces("A", WHITE, 1); game->set_maximum_number_of_pieces("E", WHITE, 1); game->set_maximum_number_of_pieces("S", WHITE, 1); game->set_maximum_number_of_pieces("V", WHITE, 1); game->set_maximum_number_of_pieces("R", WHITE, 2); game->set_maximum_number_of_pieces("N", WHITE, 2); game->set_maximum_number_of_pieces("B", WHITE, 2); game->set_maximum_number_of_pieces("Q", BLACK, 1); game->set_maximum_number_of_pieces("A", BLACK, 1); game->set_maximum_number_of_pieces("E", BLACK, 1); game->set_maximum_number_of_pieces("S", BLACK, 1); game->set_maximum_number_of_pieces("V", BLACK, 1); game->set_maximum_number_of_pieces("R", BLACK, 2); game->set_maximum_number_of_pieces("N", BLACK, 2); game->set_maximum_number_of_pieces("B", BLACK, 2); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); game->xb_setup = strdup("(PNBRQ..SE.......V.AKpnbrq..se.......v.ak) 8x8+9_fairy"); game->name = strdup("Super Chess"); game->finalise_variant(); return game; } game_t *create_test_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fa = fb | fn; move_flag_t fc = fr | fn; move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); move_flag_t fw2 = game->movegen.define_piece_move("step 2N"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,0)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fg = game->movegen.define_piece_move("aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1)"); move_flag_t fd = game->movegen.define_piece_move("leap (2,0)"); move_flag_t fe = game->movegen.define_piece_move("leap (2,2)"); move_flag_t fh = game->movegen.define_piece_move("leap ((0,1)+(1,1))&(2,1)"); move_flag_t fz = game->movegen.define_piece_move("leap (3,2)"); move_flag_t flm = game->movegen.define_piece_move("leap (0,0)|(1,1)|(1,0)|(2,0)|(2,1)|(2,2)"); move_flag_t flc = game->movegen.define_piece_move("leap ((1,1)|(1,0))+((1,1)|(1,0))"); move_flag_t fdk = fr | ff; move_flag_t fdh = fb | fw; uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N"); game->add_piece_type( fh, fh, 0, pz, "", "Horse", "H,h", "H"); game->add_piece_type( fb, fb, 0, pz, "", "Bishop", "B,b", "B"); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R"); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q"); game->add_piece_type( fa, fa, 0, pz, "", "Archbishop", "A,a", "A"); game->add_piece_type( fc, fc, 0, pz, "", "Chancellor", "C,c", "C"); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K"); game->add_piece_type( ff, ff, 0, pz, "", "Ferz", "F,f", "F"); game->add_piece_type( fw, fw, 0, pz, "", "Wazir", "W,w", "W"); game->add_piece_type( fz, fz, 0, pz, "", "Zebra", "Z,z", "Z"); game->add_piece_type( flm, flc,0, pz, "", "Lion", "L,l", "L"); game->add_piece_type( fs, fs, 0, pz, "", "Silver general", "S,s", "S"); game->add_piece_type( fg, fg, 0, pz, "", "Gold general", "G,g", "G"); game->add_piece_type( fd, fd, 0, pz, "", "Dabbabah", "D,d", "D"); //game->add_piece_type( fe, fe, 0, pz, "", "Elephant", "E,e", "E"); game->add_piece_type(fdk, fdk, 0, pz, "", "Dragon king","J,j", "J"); game->add_piece_type(fdh, fdh, 0, pz, "", "Dragon horse","I,i", "I"); game->add_piece_type(fwp, fwc, pf, pp, "QACRBN", "Pawn", "P,p", " "); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, fw2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -"); game->name = strdup("test"); game->finalise_variant(); return game; } game_t *create_shogi_game(const char *) { int files = 9; int ranks = 9; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("aleap (1,2)|(-1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fl = game->movegen.define_piece_move("step 8N"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,0)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fg = game->movegen.define_piece_move("aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1)"); move_flag_t fdk = fr | ff; move_flag_t fdh = fb | fw; uint32_t kf = PF_ROYAL; uint32_t pf = PF_DROPNOMATE | PF_DROPONEFILE; bitboard_t pp[2]; bitboard_t pz[2] = { bitboard_t::board_rank[8]|bitboard_t::board_rank[7]|bitboard_t::board_rank[6], bitboard_t::board_rank[0]|bitboard_t::board_rank[1]|bitboard_t::board_rank[2] }; float m_scale = 0.3; game->add_piece_type( fp, fp, pf, pz, "+", "Pawn", "P,p", "P", 80*m_scale);// 50); game->add_piece_type( fl, fl, 0, pz, "+", "Lance", "L,l", "L", 225*m_scale);// 200); game->add_piece_type( fn, fn, 0, pz, "+", "Knight", "N,n", "N", 250*m_scale);// 250); game->add_piece_type( fs, fs, 0, pz, "+", "Silver general", "S,s", "S", 375*m_scale);// 350); game->add_piece_type( fb, fb, 0, pz, "+", "Bishop", "B,b", "B", 575*m_scale);// 550); game->add_piece_type( fr, fr, 0, pz, "+", "Rook", "R,r", "R", 650*m_scale);// 650); game->add_piece_type( fg, fg, 0, pp, "", "Gold general", "G,g", "G", 450*m_scale);// 400); game->add_piece_type( fk, fk, kf, pp, "", "King", "K,k", "K"); game->add_piece_type( fg, fg, 0, pp, "", "Promoted pawn", "+P,+p", "+P", 530*m_scale);// 270); game->add_piece_type( fg, fg, 0, pp, "", "Promoted lance", "+L,+l", "+L", 480*m_scale);// 300); game->add_piece_type( fg, fg, 0, pp, "", "Promoted knight", "+N,+n", "+N", 500*m_scale);// 330); game->add_piece_type( fg, fg, 0, pp, "", "Promoted silver", "+S,+s", "+S", 490*m_scale);// 370); game->add_piece_type(fdh, fdh, 0, pp, "", "Dragon horse", "+B,+b", "+B", 825*m_scale);// 700); game->add_piece_type(fdk, fdk, 0, pp, "", "Dragon king", "+R,+r", "+R", 950*m_scale);// 800); game->start_fen = strdup("lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL [-] w 0 1"); game->name = strdup("shogi"); game->add_rule(RF_ALLOW_DROPS); game->add_rule(RF_KEEP_CAPTURE); /* TODO: perpetual checking is not allowed */ game->perpetual = -ILLEGAL; game->repeat_claim = 3; game->finalise_variant(); return game; } game_t *create_minishogi_game(const char *) { #define kind uint64_t unsigned int files = 5; unsigned int ranks = 5; if (8*sizeof(kind) < files*ranks) return NULL; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,0)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fg = game->movegen.define_piece_move("aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1)"); move_flag_t fdk = fr | ff; move_flag_t fdh = fb | fw; uint32_t kf = PF_ROYAL; uint32_t pf = PF_DROPNOMATE | PF_DROPONEFILE; bitboard_t pp[2]; bitboard_t pz[2] = { bitboard_t::board_rank[4], bitboard_t::board_rank[0] }; game->add_piece_type( fp, fp, pf, pz, "+", "Pawn", "P,p", "P", 100); game->add_piece_type( fs, fs, 0, pz, "+", "Silver general", "S,s", "S", 400); game->add_piece_type( fb, fb, 0, pz, "+", "Bishop", "B,b", "B", 450); game->add_piece_type( fr, fr, 0, pz, "+", "Rook", "R,r", "R", 500); game->add_piece_type( fg, fg, 0, pp, "", "Gold general", "G,g", "G", 450); game->add_piece_type( fk, fk, kf, pp, "", "King", "K,k", "K"); game->add_piece_type( fg, fg, 0, pp, "", "Promoted pawn", "+P,+p", "+P", 550); game->add_piece_type( fg, fg, 0, pp, "", "Promoted silver", "+S,+s", "+S", 500); game->add_piece_type(fdh, fdh, 0, pp, "", "Dragon horse", "+B,+b", "+B", 650); game->add_piece_type(fdk, fdk, 0, pp, "", "Dragon king", "+R,+r", "+R", 700); game->start_fen = strdup("rbsgk/4p/5/P4/KGSBR [-] w 0 1"); game->xb_setup = strdup("(P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k) 5x5+5_shogi"); game->name = strdup("minishogi"); game->add_rule(RF_ALLOW_DROPS); game->add_rule(RF_KEEP_CAPTURE); /* FIXME: repetition is scored as a loss, but it should be scored as a loss *for white*, * unless it is a check-by-repetition. */ game->rep_score = -ILLEGAL; game->repeat_claim = 3; game->finalise_variant(); return game; #undef kind } game_t *create_shoshogi_game(const char *) { int files = 9; int ranks = 9; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("aleap (1,2)|(-1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fl = game->movegen.define_piece_move("step 8N"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,0)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fg = game->movegen.define_piece_move("aleap (1,0)|(-1,0)|(0,1)|(0,-1)|(1,1)|(-1,1)"); move_flag_t fe = game->movegen.define_piece_move("aleap (1,0)|(-1,0)|(0,1)|(1,1)|(-1,1)|(1,-1)|(-1,-1)"); move_flag_t fdk = fr | ff; move_flag_t fdh = fb | fw; uint32_t kf = PF_ROYAL; uint32_t pf = PF_DROPNOMATE | PF_DROPONEFILE; bitboard_t pp[2]; bitboard_t pz[2] = { bitboard_t::board_rank[8]|bitboard_t::board_rank[7]|bitboard_t::board_rank[6], bitboard_t::board_rank[0]|bitboard_t::board_rank[1]|bitboard_t::board_rank[2] }; game->add_piece_type( fp, fp, pf, pz, "+", "Pawn", "P,p", "P", 75); game->add_piece_type( fl, fl, 0, pz, "+", "Lance", "L,l", "L", 250); game->add_piece_type( fn, fn, 0, pz, "+", "Knight", "N,n", "N", 300); game->add_piece_type( fs, fs, 0, pz, "+", "Silver general", "S,s", "S", 400); game->add_piece_type( fb, fb, 0, pz, "+", "Bishop", "B,b", "B", 650); game->add_piece_type( fr, fr, 0, pz, "+", "Rook", "R,r", "R", 750); game->add_piece_type( fe, fe, 0, pz, "+", "Drunk elephant", "E,e", "E", 550); game->add_piece_type( fg, fg, 0, pp, "", "Gold general", "G,g", "G", 450); game->add_piece_type( fk, fk, kf, pp, "", "King", "K,k", "K"); game->add_piece_type( fg, fg, 0, pp, "", "Promoted pawn", "+P,+p", "+P", 450); game->add_piece_type( fg, fg, 0, pp, "", "Promoted lance", "+L,+l", "+L", 450); game->add_piece_type( fg, fg, 0, pp, "", "Promoted knight", "+N,+n", "+N", 450); game->add_piece_type( fg, fg, 0, pp, "", "Promoted silver", "+S,+s", "+S", 450); game->add_piece_type( fk, fk, kf, pp, "", "Crown prince", "+E,+e", "+E", 700); game->add_piece_type(fdh, fdh, 0, pp, "", "Dragon horse", "+B,+b", "+B", 775); game->add_piece_type(fdk, fdk, 0, pp, "", "Dragon king", "+R,+r", "+R", 900); game->start_fen = strdup("lnsgkgsnl/1r2e2b1/ppppppppp/9/9/9/PPPPPPPPP/1B2E2R1/LNSGKGSNL [-] w 0 1"); game->xb_setup = strdup("(PNBRLSE..G.+.++.++Kpnbrlse..g.+.++.++k) 9x9+0_shogi"); game->name = strdup("shoshogi"); game->add_rule(RF_USE_BARERULE); game->bare_king_score = -LEGALWIN; game->repeat_claim = 3; game->finalise_variant(); return game; } game_t *create_tori_game(const char *) { int files = 7; int ranks = 7; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t flq = game->movegen.define_piece_move("step 6N,6SE,SW"); // Left Quail move_flag_t frq = game->movegen.define_piece_move("step 6N,6SW,SE"); // Right Quail move_flag_t fs = game->movegen.define_piece_move("step N"); move_flag_t ff = game->movegen.define_piece_move("aleap (-1,-1)|(-1,0)|(-1,1)|(0,1)|(1,1)|(1,0)|(1,-1)"); move_flag_t fc = game->movegen.define_piece_move("aleap (-1,-1)|(0,-1)|(-1,1)|(1,1)|(0,1)|(1,-1)"); move_flag_t fe = game->movegen.define_piece_move("step 6NE,6NW,6S,2SE,2SW") | fk; move_flag_t fp = game->movegen.define_piece_move("aleap (-1,-1)|(1,-1)|(0,2)"); move_flag_t fg = game->movegen.define_piece_move("aleap (2,2)|(-2,2)|(0,-2)"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_DROPNOMATE | PF_DROPONEFILE; bitboard_t pz[2]; bitboard_t pp[2] = { bitboard_t::board_rank[6]|bitboard_t::board_rank[5], bitboard_t::board_rank[0]|bitboard_t::board_rank[1] }; game->add_piece_type( fk, fk, kf, pz, "", "Phoenix", "K,k", "K"); game->add_piece_type( ff, ff, 0, pp, "+", "Falcon", "F,f", "F"); game->add_piece_type( fc, fc, 0, pz, "", "Crane", "C,c", "C"); game->add_piece_type(flq, flq, 0, pz, "", "Left quail", "L,l", "L"); game->add_piece_type(frq, frq, 0, pz, "", "Right quail","R,r", "R"); game->add_piece_type( fp, fp, 0, pz, "", "Pheasant", "P,p", "P"); int st = game->add_piece_type( fs, fs, pf, pp, "+", "Swallow", "S,s", "S"); game->add_piece_type( fg, fg, 0, pz, "", "Goose", "+S,+s","+S"); game->add_piece_type( fe, fe, 0, pz, "", "Eagle", "+F,+f","+F"); game->pt.piece_drop_file_maximum[st] = 2; game->start_fen = strdup("rpckcpl/3f3/sssssss/2s1S2/SSSSSSS/3F3/LPCKCPR [-] w 0 1"); game->xb_setup = strdup("(S.....FLR.C+.....+.PKs.....flr.c+.....+.pk) 7x7+6_shogi"); game->name = strdup("Tori Shogi"); game->add_rule(RF_ALLOW_DROPS); game->add_rule(RF_KEEP_CAPTURE); // TODO: repetition rules game->rep_score = -ILLEGAL; game->finalise_variant(); return game; } game_t *create_chinese_game(const char *) { int files = 9; int ranks = 10; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fc = game->movegen.define_piece_move("hop (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap ((0,1)+(1,1))&(1,2)"); move_flag_t fe = game->movegen.define_piece_move("leap ((1,1)+(1,1))&(2,2)"); move_flag_t ff = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)"); move_flag_t fp = game->movegen.define_piece_move("aleap (1,0)|(-1,0)|(0,1)"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; game->add_piece_type(fn, fn, 0, pz, "", "Horse", "H,h", "H", 400); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 950); game->add_piece_type(fr, fc, 0, pz, "", "Cannon", "C,c", "C", 450); int gi = game->add_piece_type(ff, ff, 0, pz, "", "Guard", "A,a", "G", 150); int ei = game->add_piece_type(fe, fe, 0, pz, "", "Elephant", "E,e", "E", 150); int pi = game->add_piece_type(fp, fp, 0, pz, "", "Pawn", "P,p", "P", 100); int ki = game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); /* Zones for restricted piece movement */ bitboard_t south = bitboard_t::board_south; bitboard_t north = bitboard_t::board_north;; bitboard_t pawnf; for (int f = 0; f::board_file[f]; /* Guards and kings are restricted to the castles */ bitboard_t palace; for (int r = 0; r<=2; r++) for (int f = 3; f<=5; f++) { palace.set(f + 9*r); palace.set(f + 9*(9-r)); } game->pt.prison[WHITE][ki] = palace & south; game->pt.prison[BLACK][ki] = palace & north; game->pt.prison[WHITE][gi] = palace & south; game->pt.prison[BLACK][gi] = palace & north; game->pt.prison[WHITE][ei] = south; game->pt.prison[BLACK][ei] = north; game->pt.prison[WHITE][pi] = pawnf | north; game->pt.prison[BLACK][pi] = pawnf | south; game->add_rule(RF_KING_TABOO | RF_KING_TRAPPED | RF_USE_CHASERULE); game->start_fen = strdup("rheakaehr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RHEAKAEHR w - - 0 1"); game->name = strdup("XiangQi"); game->stale_score = LEGALWIN; //game->rep_score = -LEGALWIN; game->finalise_variant(); return game; } game_t *create_grand_game(const char *) { int files = 10; int ranks = 10; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fq = fb | fr; move_flag_t fc = fb | fn; move_flag_t fm = fr | fn; move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); move_flag_t fw2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pi[2] = {bitboard_t::board_rank[2], bitboard_t::board_rank[7]}; bitboard_t pp[2] = {bitboard_t::board_rank[7]|bitboard_t::board_rank[8]|bitboard_t::board_rank[9], bitboard_t::board_rank[0]|bitboard_t::board_rank[1]|bitboard_t::board_rank[2]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 275); game->add_piece_type( fb, fb, 0, pz, "", "Bishop", "B,b", "B", 350); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R", 475); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 950); game->add_piece_type( fc, fc, 0, pz, "", "Cardinal", "C,c", "C", 825); game->add_piece_type( fm, fm, 0, pz, "", "Marshal", "M,m", "M", 875); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fwp, fwc, pf, pp, "QMCRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, fw2); game->set_maximum_number_of_pieces("Q", WHITE, 1); game->set_maximum_number_of_pieces("M", WHITE, 1); game->set_maximum_number_of_pieces("C", WHITE, 1); game->set_maximum_number_of_pieces("R", WHITE, 2); game->set_maximum_number_of_pieces("N", WHITE, 2); game->set_maximum_number_of_pieces("B", WHITE, 2); game->set_maximum_number_of_pieces("Q", BLACK, 1); game->set_maximum_number_of_pieces("M", BLACK, 1); game->set_maximum_number_of_pieces("C", BLACK, 1); game->set_maximum_number_of_pieces("R", BLACK, 2); game->set_maximum_number_of_pieces("N", BLACK, 2); game->set_maximum_number_of_pieces("B", BLACK, 2); game->start_fen = strdup("r8r/1nbqkmcbn1/pppppppppp/10/10/10/10/PPPPPPPPPP/1NBQKMCBN1/R8R w - -"); game->name = strdup("Grand chess"); game->finalise_variant(); return game; } // http://www.chessvariants.org/index/msdisplay.php?itemid=MSopulentchess game_t *create_opulent_game(const char *) { int files = 10; int ranks = 10; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)|leap(1,0)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,3)|leap(1,1)"); move_flag_t fl = game->movegen.define_piece_move("leap (0,2)|(0,3)|leap(1,1)"); move_flag_t fN = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fq = fb | fr; move_flag_t fa = fb | fN; move_flag_t fc = fr | fN; move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); move_flag_t fw2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pi[2] = {bitboard_t::board_rank[2], bitboard_t::board_rank[7]}; bitboard_t pp[2] = {bitboard_t::board_rank[7]|bitboard_t::board_rank[8]|bitboard_t::board_rank[9], bitboard_t::board_rank[0]|bitboard_t::board_rank[1]|bitboard_t::board_rank[2]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 300); game->add_piece_type( fw, fw, 0, pz, "", "Wizard", "W,w", "W", 300); game->add_piece_type( fl, fl, 0, pz, "", "Lion", "L,l", "L", 300); game->add_piece_type( fb, fb, 0, pz, "", "Bishop", "B,b", "B", 350); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R", 475); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 950); game->add_piece_type( fa, fa, 0, pz, "", "Archbishop","A,a", "A", 825); game->add_piece_type( fc, fc, 0, pz, "", "Chancellor","C,c", "C", 875); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fwp, fwc, pf, pp, "QACRBNWL", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, fw2); game->set_maximum_number_of_pieces("Q", WHITE, 1); game->set_maximum_number_of_pieces("C", WHITE, 1); game->set_maximum_number_of_pieces("A", WHITE, 1); game->set_maximum_number_of_pieces("R", WHITE, 2); game->set_maximum_number_of_pieces("N", WHITE, 2); game->set_maximum_number_of_pieces("B", WHITE, 2); game->set_maximum_number_of_pieces("W", WHITE, 2); game->set_maximum_number_of_pieces("L", WHITE, 2); game->set_maximum_number_of_pieces("Q", BLACK, 1); game->set_maximum_number_of_pieces("M", BLACK, 1); game->set_maximum_number_of_pieces("C", BLACK, 1); game->set_maximum_number_of_pieces("R", BLACK, 2); game->set_maximum_number_of_pieces("N", BLACK, 2); game->set_maximum_number_of_pieces("B", BLACK, 2); game->set_maximum_number_of_pieces("W", BLACK, 2); game->set_maximum_number_of_pieces("L", BLACK, 2); game->start_fen = strdup("rw6wr/clbnqknbla/pppppppppp/10/10/10/10/PPPPPPPPPP/CLBNQKNBLA/RW6WR w - -"); game->xb_setup = strdup("(PNBRQ..AC....W.......LKpnbrq..ac....w.......lk) 10x10+0_grand"); game->name = strdup("Opulent chess"); game->finalise_variant(); return game; } game_t *create_greatshatranj_game(const char *) { int files = 10; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fg = game->movegen.define_piece_move("leap (1,0)|(1,1)|(2,0)|(2,2)"); move_flag_t fm = game->movegen.define_piece_move("leap (1,0)|(2,0)|(1,2)"); move_flag_t fh = game->movegen.define_piece_move("leap (1,1)|(2,2)|(1,2)"); move_flag_t fe = game->movegen.define_piece_move("leap (1,1)|(2,2)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,0)|(2,0)"); move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type( fg, fg, 0, pz, "", "General", "G,g", "G", 650); game->add_piece_type( fm, fm, 0, pz, "", "Minister", "M,m", "M", 650); game->add_piece_type( fh, fh, 0, pz, "", "High Priest","H,h","H", 650); game->add_piece_type( fe, fe, 0, pz, "", "Elephant", "E,e", "E", 300); game->add_piece_type( fw, fw, 0, pz, "", "Woody", "W,w", "W", 300); game->add_piece_type( fk, fk, 0, pz, "", "Soldier", "S,s", "S", 300); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fwp, fwc, 0, pp, "NGMHEWS","Pawn", "P,p", " ", 100); game->set_maximum_number_of_pieces("N", WHITE, 2); game->set_maximum_number_of_pieces("G", WHITE, 1); game->set_maximum_number_of_pieces("M", WHITE, 1); game->set_maximum_number_of_pieces("H", WHITE, 1); game->set_maximum_number_of_pieces("E", WHITE, 2); game->set_maximum_number_of_pieces("W", WHITE, 2); game->set_maximum_number_of_pieces("N", BLACK, 2); game->set_maximum_number_of_pieces("G", BLACK, 1); game->set_maximum_number_of_pieces("M", BLACK, 1); game->set_maximum_number_of_pieces("H", BLACK, 1); game->set_maximum_number_of_pieces("E", BLACK, 2); game->set_maximum_number_of_pieces("W", BLACK, 2); game->start_fen = strdup("wnegkmhenw/pppppppppp/10/10/10/10/PPPPPPPPPP/WNEGKMHENW w KQkq - 0 1"); game->xb_setup = strdup("(PN....E...S..HWGMKpn....e...s..hwgmk)"); game->name = strdup("Great Shatranj"); game->finalise_variant(); return game; } game_t *create_capablanca_game(const char *) { int files = 10; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fq = fb | fr; move_flag_t fa = fb | fn; move_flag_t fc = fr | fn; move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); move_flag_t fw2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 275); game->add_piece_type( fb, fb, 0, pz, "", "Bishop", "B,b", "B", 350); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R", 475); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 950); game->add_piece_type( fa, fa, 0, pz, "", "Archbishop","A,a", "A", 825); game->add_piece_type( fc, fc, 0, pz, "", "Chancellor","C,c", "C", 875); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fwp, fwc, pf, pp, "QACRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, fw2); game->deduce_castle_flags(WHITE, 5, 8, 9); game->deduce_castle_flags(WHITE, 5, 2, 0); game->deduce_castle_flags(BLACK, 75, 78, 79); game->deduce_castle_flags(BLACK, 75, 72, 0); game->start_fen = strdup("rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR w KQkq -"); game->name = strdup("Capablanca chess"); game->finalise_variant(); return game; } game_t *create_gothic_game(const char *shortname) { game_t *game = create_capablanca_game(shortname); if (game) { free(game->start_fen); free(game->name); game->start_fen = strdup("rnbqckabnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBQCKABNR w KQkq -"); game->name = strdup("Capablanca chess (Gothic)"); } return game; } game_t *create_embassy_game(const char *shortname) { game_t *game = create_capablanca_game(shortname); if (game) { free(game->start_fen); free(game->name); game->start_fen = strdup("rnbqkcabnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBQKCABNR w KQkq -"); game->xb_setup = strdup("(PNBRQ..AC............Kpnbrq..ac............k) 10x8+0_capablanca"); game->name = strdup("Capablanca chess (Embassy)"); game->deduce_castle_flags(WHITE, 4, 1, 0); game->deduce_castle_flags(WHITE, 4, 7, 9); game->deduce_castle_flags(BLACK, 74, 71, 70); game->deduce_castle_flags(BLACK, 74, 77, 79); } return game; } game_t *create_micro_game(const char *) { #define kind uint64_t int files = 5; int ranks = 5; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fq = fb | fr; move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[4], bitboard_t::board_rank[0]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type( fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fwp, fwc, 0, pp, "QRBN", "Pawn", "P,p", " ", 100); game->start_fen = strdup("kqbnr/ppppp/5/PPPPP/KQBNR w - -"); game->xb_setup = strdup("(PNBRQKpnbrqk) 5x5+0_fairy"); game->name = strdup("Gardner minichess"); // http://www.chessvariants.org/small.dir/hpmini.html game->finalise_variant(); return game; #undef kind } game_t *create_losalamos_game(const char *) { int files = 6; int ranks = 6; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fq = fb | fr; move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fwp = game->movegen.define_piece_move("step N"); move_flag_t fwc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[5], bitboard_t::board_rank[0]}; game->add_piece_type( fn, fn, 0, pz, "", "Knight", "N,n", "N", 575); game->add_piece_type( fr, fr, 0, pz, "", "Rook", "R,r", "R", 650); game->add_piece_type( fq, fq, 0, pz, "", "Queen", "Q,q", "Q",1220); game->add_piece_type( fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fwp, fwc, 0, pp, "QRN", "Pawn", "P,p", " ", 100); game->start_fen = strdup("rnqknr/pppppp/6/6/PPPPPP/RNQKNR w - -"); game->xb_setup = strdup("(PN.RQ................Kpn.rq................k) 6x6+0_fairy"); game->name = strdup("Los Alamos chess"); game->finalise_variant(); return game; } game_t *create_pocketknight_game(const char *shortname) { game_t *game = create_standard_game(shortname); if (game) { free(game->start_fen); free(game->name); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR [Nn] w KQkq -"); game->xb_setup = strdup("(PNBRQKpnbrqk) 8x8+2_bughouse"); // Hack: we need a holding-size of 2, otherwise the knight drops out. game->name = strdup("Pocket Knight Chess"); game->add_rule(RF_ALLOW_DROPS); } return game; } game_t *create_kingofthehill_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 2N"); uint32_t kf = PF_ROYAL | PF_CAPTUREFLAG; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[6]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 325); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, pf, pp, "QRBN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 4, 6, 7); game->deduce_castle_flags(WHITE, 4, 2, 0); game->deduce_castle_flags(BLACK, 60, 62, 63); game->deduce_castle_flags(BLACK, 60, 58, 56); for (side_t side=WHITE; side<=BLACK; side++) { game->place_flag(side, 27); game->place_flag(side, 28); game->place_flag(side, 35); game->place_flag(side, 36); } game->add_rule(RF_CAPTURE_ANY_FLAG); game->start_fen = strdup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); game->xb_setup = strdup("(PNBRQKpnbrqk) 8x8+0_fairy"); game->name = strdup("King of the hill"); game->finalise_variant(); return game; } game_t *create_sittuyin_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fm = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t diag = bitboard_t::board_diagonal[7] | bitboard_t::board_antidiagonal[7]; bitboard_t pz[2]; bitboard_t pp[2] = { diag & diag.board_homeland[BLACK], diag & diag.board_homeland[WHITE] }; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fs, fs, 0, pz, "", "Silver general", "S,s", "S", 275); game->add_piece_type(fm, fm, 0, pz, "", "Ferz", "F,f", "F", 100); int ri = game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "F", "Pawn", "P,p", " ", 80); game->add_rule(RF_FORCE_DROPS | RF_PROMOTE_IN_PLACE); game->set_maximum_number_of_pieces("F", WHITE, 1); game->set_maximum_number_of_pieces("F", BLACK, 1); for (int n = 0; npt.num_piece_types; n++) { if (n == ri) { game->pt.drop_zone[WHITE][n] = bitboard_t::board_rank[0]; game->pt.drop_zone[BLACK][n] = bitboard_t::board_rank[7]; } else { game->pt.drop_zone[WHITE][n] = bitboard_t::board_rank[1] | bitboard_t::board_rank[2]; game->pt.drop_zone[BLACK][n] = bitboard_t::board_rank[6] | bitboard_t::board_rank[5]; } game->pt.optional_promotion_zone[WHITE][n] = game->pt.promotion_zone[WHITE][n]; game->pt.optional_promotion_zone[BLACK][n] = game->pt.promotion_zone[BLACK][n]; } /* Set the FEN string for the starting position */ game->start_fen = strdup("8/8/4pppp/pppp4/4PPPP/PPPP4/8/8[KFRRSSNNkfrrssnn] w - - 0 1"); game->xb_setup = strdup("(PN.R.F....SKpn.r.f....sk) 8x8+6_bughouse"); game->name = strdup("Sittuyin"); game->finalise_variant(); return game; } game_t *create_makruk_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fm = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[5], bitboard_t::board_rank[2]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fs, fs, 0, pz, "", "Silver general", "S,s", "S", 275); game->add_piece_type(fm, fm, 0, pz, "", "Met", "M,m", "M", 150); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "M", "Pawn", "P,p", " ", 80); /* Set the FEN string for the starting position */ game->start_fen = strdup("rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w - -"); game->name = strdup("Makruk"); game->finalise_variant(); /* Sixth-rank promotions are never optional */ for (int n = 0; npt.num_piece_types; n++) { game->pt.optional_promotion_zone[WHITE][n].clear(); game->pt.optional_promotion_zone[BLACK][n].clear(); } return game; } game_t *create_aiwok_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fa = game->movegen.define_piece_move("leap (1,1)|(1,2)") | fr; move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[5], bitboard_t::board_rank[2]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fs, fs, 0, pz, "", "Silver general", "S,s", "S", 275); game->add_piece_type(fa, fa, 0, pz, "", "Ai-Wok", "A,a", "A",1050); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "A", "Pawn", "P,p", " ", 80); /* Set the FEN string for the starting position */ game->start_fen = strdup("rnsaksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKASNR w - -"); game->xb_setup = strdup("(PN.R...A..SKpn.r...a..sk) 8x8+0_makruk"); game->name = strdup("Ai-Wok"); game->finalise_variant(); /* Sixth-rank promotions are never optional */ for (int n = 0; npt.num_piece_types; n++) { game->pt.optional_promotion_zone[WHITE][n].clear(); game->pt.optional_promotion_zone[BLACK][n].clear(); } return game; } game_t *create_asean_game(const char *) { int files = 8; int ranks = 8; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fm = game->movegen.define_piece_move("leap (1,1)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fs = game->movegen.define_piece_move("aleap (0,1)|(1,1)|(1,-1)|(-1,-1)|(-1,1)"); move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); uint32_t kf = PF_ROYAL; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[7], bitboard_t::board_rank[0]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 325); game->add_piece_type(fs, fs, 0, pz, "", "Bishop", "B,b", "B", 275); game->add_piece_type(fm, fm, 0, pz, "", "Queen", "Q,q", "Q", 150); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 500); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); game->add_piece_type(fp, fc, 0, pp, "QRBN", "Pawn", "P,p", " ", 80); /* Set the FEN string for the starting position */ game->start_fen = strdup("rnbqkbnr/8/pppppppp/8/8/PPPPPPPP/8/RNBQKBNR w - -"); game->name = strdup("ASEAN"); game->finalise_variant(); return game; } game_t *create_omega_game(const char *) { int files = 12; int ranks = 10; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); move_flag_t fb = game->movegen.define_piece_move("slide (A,D)"); move_flag_t fr = game->movegen.define_piece_move("slide (H,V)"); move_flag_t fn = game->movegen.define_piece_move("leap (1,2)"); move_flag_t fk = game->movegen.define_piece_move("leap (1,0)|(1,1)"); move_flag_t fh = game->movegen.define_piece_move("leap (0,1)|(0,2)|(2,2)"); move_flag_t fw = game->movegen.define_piece_move("leap (1,1)|(1,3)"); move_flag_t fq = fb | fr; move_flag_t fp = game->movegen.define_piece_move("step N"); move_flag_t fc = game->movegen.define_piece_move("step NE, NW"); move_flag_t f2 = game->movegen.define_piece_move("step 3N"); uint32_t kf = PF_ROYAL; uint32_t pf = PF_SET_EP | PF_TAKE_EP; bitboard_t pz[2]; bitboard_t pp[2] = {bitboard_t::board_rank[9], bitboard_t::board_rank[0]}; bitboard_t pi[2] = {bitboard_t::board_rank[1], bitboard_t::board_rank[8]}; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N", 250); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B", 400); game->add_piece_type(fw, fw, 0, pz, "", "Wizard", "W,w", "W", 350); game->add_piece_type(fh, fh, 0, pz, "", "Champion", "C,c","C", 375); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R", 600); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q", 975); game->add_piece_type(fk, fk, kf, pz, "", "King", "K,k", "K", 0); int ind = game->add_piece_type(fp, fc, pf, pp, "QRBCWN", "Pawn", "P,p", " ", 100); /* Add special move types for pawns on their initial squares */ game->add_special_move("P", pi, f2); game->deduce_castle_flags(WHITE, 6, 8, 9); game->deduce_castle_flags(WHITE, 6, 4, 2); game->deduce_castle_flags(BLACK, 114, 116, 117); game->deduce_castle_flags(BLACK, 114, 112, 110); /* Now hack the movement tables to off-set the wizard squares by one rank */ bitboard_t ws = bitboard_t::board_corner; bitboard_t bb; for (int n=0; n<16; n++) { bitboard_t::board_rank[n] &= ~ws; bitboard_t::board_file[n] &= ~ws; } for (int n=0; n<32; n++) { bitboard_t::board_diagonal[n] &= ~ws; bitboard_t::board_antidiagonal[n] &= ~ws; } bitboard_t::board_dark ^= ws; bitboard_t::board_light ^= ws; /* Remap the wizard squares on the diagonals */ bitboard_t::diagonal_nr[0]--; bitboard_t::diagonal_nr[files*ranks-1]++; bitboard_t::anti_diagonal_nr[files-1]--; bitboard_t::anti_diagonal_nr[files*(ranks-1)]++; for (int n=0; n<32; n++) { bitboard_t::board_diagonal[n].clear(); bitboard_t::board_antidiagonal[n].clear(); } for (int sq=0; sq::diagonal_nr[sq]; bitboard_t::board_diagonal[n].set(sq); n = bitboard_t::anti_diagonal_nr[sq]; bitboard_t::board_antidiagonal[n].set(sq); } /* Adjust leaper tables */ for (int n=0; n<8; n++) game->movegen.step_mask[n] &=~ws; for (int n=0; nmovegen.number_of_leapers; n++) { for (int s=0; smovegen.leaper[n][s] &= ~ws; } for (int n=0; nmovegen.number_of_aleapers; n++) { for (int s=0; smovegen.aleaper[WHITE][n][s] &= ~ws; game->movegen.aleaper[BLACK][n][s] &= ~ws; } } for (int n=0; nmovegen.number_of_steppers; n++) { for (int s=0; smovegen.stepper_step[n][WHITE][s] &= ~ws; game->movegen.stepper_step[n][BLACK][s] &= ~ws; } } /* Correct leaper tables for wizard squares */ bb = ws & bitboard_t::board_south; while (!bb.is_empty()) { int sq = bb.bitscan(); bb.reset(sq); for (int n=0; nmovegen.number_of_leapers; n++) { bitboard_t moves = game->movegen.leaper[n][sq] >> files; game->movegen.leaper[n][sq] = moves; while (!moves.is_empty()) { int s2 = moves.bitscan(); moves.reset(s2); game->movegen.leaper[n][s2].set(sq); } } } bb = ws & bitboard_t::board_north; while (!bb.is_empty()) { int sq = bb.bitscan(); bb.reset(sq); for (int n=0; nmovegen.number_of_leapers; n++) { bitboard_t moves = game->movegen.leaper[n][sq] << files; game->movegen.leaper[n][sq] = moves; while (!moves.is_empty()) { int s2 = moves.bitscan(); moves.reset(s2); game->movegen.leaper[n][s2].set(sq); } } } /* Pawns can never reach wizard squares */ game->pt.prison[WHITE][ind] &= ~ws; game->pt.prison[BLACK][ind] &= ~ws; /* Map squares on the 12x12 board to the 12x10 bitboard representation */ game->virtual_files = 12; game->virtual_ranks = 12; for (int sq = 0; sq<12*12; sq++) game->square_to_bit[sq] = -1; game->top_left = 12*11; for (int r = 0; rsquare_to_bit[sq] = bit; } bb = (bitboard_t::board_east_edge | bitboard_t::board_west_edge) & ~ws; while (!bb.is_empty()) { int sq = bb.bitscan(); bb.reset(sq); game->remove_square(sq); } game->start_fen = strdup("wcrnbqkbnrcw/*pppppppppp*/*10*/*10*/*10*/*10*/*10*/*10*/*PPPPPPPPPP*/WCRNBQKBNRCW w KQkq -"); game->start_fen = strdup("w**********w/*crnbqkbnrc*/*pppppppppp*/*10*/*10*/*10*/*10*/*10*/*10*/*PPPPPPPPPP*/*CRNBQKBNRC*/W**********W w KQkq -"); game->xb_setup = strdup("(PNBRQ..C.W...........Kpnbrq..c.w...........k) 12x12+0_fairy"); game->name = strdup("Omega chess"); game->finalise_variant(); /* Relabel squares so their names are consistent with the 12x12 board rather than the 12x10 */ for (int n=0; n<128; n++) if (square_names[n]) square_names[n][0] = 0; for (int r = 0; r<12; r++) { for (int f = 0; f<12; f++) { //printf("% 4d ", game->square_to_bit[f+r*12]); if (game->square_to_bit[f+r*12] >= 0) { snprintf(square_names[game->square_to_bit[f+r*12]], 10, "%c%d", 'a'+f, 1+r); //printf("%4s", square_names[game->square_to_bit[f+r*12]]); } else { //printf(" "); } } //printf("\n"); } keep_labels = true; return game; } template struct file_piece_description_t { bitboard_t special_zone[2]; bitboard_t promotion_zone[2]; bitboard_t optional_promotion_zone[2]; bitboard_t prison_zone[2]; bitboard_t drop_zone[2]; char *name; char *abbr; char *symbol; char *promotion; char *demotion; move_flag_t move, capture, special; uint32_t flags; int value; int max[2]; bool set_capture; bool set_prison; bool set_optional_promotion; bool set_drop_zone; }; template struct board_zone_description_t { char *name; bitboard_t zone; }; template static void add_piece_to_game(game_template_t *game, const file_piece_description_t *pd) { move_flag_t cflags = pd->move; if (pd->set_capture) cflags = pd->capture; int id = game->add_piece_type(pd->move, cflags, pd->flags, pd->promotion_zone, pd->promotion, pd->name, pd->symbol, pd->abbr, pd->value); if (pd->special) { char *s = strdup(pd->symbol); char *p = strchr(s, ','); if (p) *p = 0; game->add_special_move(s, pd->special_zone, pd->special); free(s); } if (pd->max[WHITE] > 0) game->pt.piece_maximum[id][WHITE] = pd->max[WHITE]; if (pd->max[BLACK] > 0) game->pt.piece_maximum[id][BLACK] = pd->max[BLACK]; if (pd->set_prison) { game->pt.prison[WHITE][id] = pd->prison_zone[WHITE]; game->pt.prison[BLACK][id] = pd->prison_zone[BLACK]; } if (pd->set_drop_zone) { game->pt.drop_zone[WHITE][id] = pd->drop_zone[WHITE]; game->pt.drop_zone[BLACK][id] = pd->drop_zone[BLACK]; } if (pd->set_optional_promotion) { game->pt.optional_promotion_zone[WHITE][id] = pd->optional_promotion_zone[WHITE]; game->pt.optional_promotion_zone[BLACK][id] = pd->optional_promotion_zone[BLACK]; game->pt.promotion_zone[WHITE][id] |= pd->optional_promotion_zone[WHITE]; game->pt.promotion_zone[BLACK][id] |= pd->optional_promotion_zone[BLACK]; game->pt.pzset[id] = true; } if (pd->demotion) game->pt.demotion_string[id] = strdup(pd->demotion); } template game_template_t *parse_game_description(FILE *f, const char *variant_name, int files, int ranks) { board_zone_description_t zone[8*sizeof(kind)+2]; file_piece_description_t *pd = NULL; int num_zones = 0; game_template_t *game = new game_template_t; game->set_board_size(files, ranks); game->name = strdup(variant_name); char line[4096]; zone[num_zones].name = strdup("empty"); zone[num_zones].zone.clear(); num_zones++; zone[num_zones].name = strdup("all"); zone[num_zones].zone = bitboard_t::board_all; num_zones++; while (!feof(f)) { if (fgets(line, sizeof line, f) == 0) continue; /* Strip away comments */ char *s = strstr(line, "#"); if (s) s[0] = '\0'; /* Snip end-of-line */ s = strstr(line, "\n"); if (s) s[0] = '\0'; /* Strip trailing space */ s = line+strlen(line)-1; while (s > line && isspace(s[0])) { s[0] = '\0'; s--; } /* New variant - we are done */ if (strstr(line, "Variant:") == line) { break; } /* Empty line, terminates a piece description */ if (line[0] == '\0' && pd) { assert(game); add_piece_to_game(game, pd); free(pd->name); free(pd->abbr); free(pd->symbol); free(pd->promotion); free(pd->demotion); free(pd); pd = NULL; } /* Set board size - can't occur more than once!*/ if (strstr(line, "Board:") == line) { delete game; return NULL; } /* Starting position (FEN) */ if (strstr(line, "FEN:") == line) { char *s = line+4; s = strstr(s, "\""); if (!s) continue; s++; char *eof = strstr(s, "\""); if (!eof) continue; eof[0] = '\0'; game->start_fen = strdup(s); if (game->xb_setup == NULL) game->xb_setup = strdup("(PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk)"); continue; } /* Piece description for XBoard */ if ((strstr(line, "XBoard pieces:") == line) || (strstr(line, "WinBoard pieces:") == line)) { char *s = line+14; s = strstr(s, "\""); if (!s) continue; s++; char *eof = strstr(s, "\""); if (!eof) continue; eof[0] = '\0'; size_t len = eof - s; free(game->xb_setup); game->xb_setup = (char *)malloc(len+4); snprintf(game->xb_setup, len+3, "(%s)", s); continue; } /* Piece description for XBoard */ if ((strstr(line, "XBoard parent:") == line) || (strstr(line, "WinBoard parent:") == line)) { char *s = line+14; s = strstr(s, "\""); if (!s) continue; s++; char *eof = strstr(s, "\""); if (!eof) continue; eof[0] = '\0'; free(game->xb_parent); game->xb_parent = (char *)malloc(51); snprintf(game->xb_parent, 50, "%s", s); continue; } /* Define a region of the board */ if (strstr(line, "Zone:") == line) { char *name = line+5; while(isspace(*name)) name++; char *s = strstr(name, "="); char *sq; if (!s) continue; sq = s+1; s[0] = '\0'; s--; while(isspace(*s)) s--; s[1] = '\0'; zone[num_zones].name = strdup(name); s = strtok(sq, ","); while(isspace(*s)) s++; char file; int rank; sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; zone[num_zones].zone.clear(); zone[num_zones].zone.set(game->pack_rank_file(rank, file)); while ((s = strtok(NULL, ","))) { sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; zone[num_zones].zone.set(game->pack_rank_file(rank, file)); } num_zones++; continue; } /* Exclude a region on the board (for the purpose of move generation) */ if (strstr(line, "Exclude:") == line) { char *s = line+8; while(isspace(*s)) s++; char *sq = s; char file; int rank; s = strtok(sq, ","); while(isspace(*s)) s++; sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; game->remove_square(game->pack_rank_file(rank, file)); while ((s = strtok(NULL, ","))) { sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; game->remove_square(game->pack_rank_file(rank, file)); } continue; } /* Capture-the-flag, white flag (for black to capture) */ if (strstr(line, "WhiteFlag:") == line) { char *s = line+10; while(isspace(*s)) s++; char *sq = s; char file; int rank; s = strtok(sq, ","); sscanf(sq, "%c%d", &file, &rank); file -= 'a'; rank--; game->place_flag(BLACK, game->pack_rank_file(rank, file)); while ((s = strtok(NULL, ","))) { sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; game->place_flag(BLACK, game->pack_rank_file(rank, file)); } continue; } /* Capture-the-flag, black flag (for white to capture) */ if (strstr(line, "BlackFlag:") == line) { char *s = line+10; while(isspace(*s)) s++; char *sq = s; char file; int rank; s = strtok(sq, ","); sscanf(sq, "%c%d", &file, &rank); file -= 'a'; rank--; game->place_flag(WHITE, game->pack_rank_file(rank, file)); while ((s = strtok(NULL, ","))) { sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; game->place_flag(WHITE, game->pack_rank_file(rank, file)); } continue; } /* Define a new piece */ if (strstr(line, "Piece:") == line) { if (pd) { add_piece_to_game(game, pd); free(pd->name); free(pd->abbr); free(pd->symbol); free(pd->promotion); free(pd->demotion); free(pd); } pd = (file_piece_description_t *)calloc(1, sizeof *pd); s = line + 6; while(isspace(*s)) s++; while(*s == ' ') s++; pd->name = strdup(s); for (side_t side = WHITE; side < NUM_SIDES; side++) { pd->prison_zone[side] = bitboard_t::board_all; pd->drop_zone[side] = bitboard_t::board_all; } continue; } if (strstr(line, "Move:") == line && pd) { s = line + 5; while(*s && isspace(*s)) s++; pd->move |= game->movegen.define_piece_move(s); continue; } if (strstr(line, "Drop zone:") == line && pd) { s = line + 7; while (isspace(*s)) s++; char *p = strstr(s, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; ndrop_zone[WHITE] = zone[n].zone; break; } s = p; while (isspace(*s)) s++; p = strstr(p, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; ndrop_zone[BLACK] = zone[n].zone; break; } pd->set_drop_zone = true; /* Do not override the drop table to remove the graveyard */ pd->flags |= PF_DROPDEAD; } if (strstr(line, "Prison:") == line && pd) { s = line + 7; while (isspace(*s)) s++; char *p = strstr(s, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; nprison_zone[WHITE] = zone[n].zone; break; } s = p; while (isspace(*s)) s++; p = strstr(p, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; nprison_zone[BLACK] = zone[n].zone; break; } pd->set_prison = true; } if (strstr(line, "Special:") == line && pd) { s = line + 8; while (isspace(*s)) s++; char *p = strstr(s, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; nspecial_zone[WHITE] = zone[n].zone; break; } s = p; while (isspace(*s)) s++; p = strstr(p, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; nspecial_zone[BLACK] = zone[n].zone; break; } while (isspace(*p)) p++; pd->special |= game->movegen.define_piece_move(p); continue; } if (strstr(line, "Capture:") == line && pd) { s = line + 8; while(isspace(*s)) s++; pd->capture |= game->movegen.define_piece_move(s); pd->set_capture = true; continue; } if (strstr(line, "Castle:") == line && pd) { side_t side = WHITE; int from, to, rfrom; char file; int rank; s = line + 7; while(isspace(*s)) s++; /* Field 1: side */ if (strstr(s, "black") == s) side = BLACK; s += 5; /* From square */ while(isspace(*s)) s++; sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; from = game->pack_rank_file(rank, file); /* To square */ s = strstr(s, "-"); if (!s) continue; s++; while(isspace(*s)) s++; sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; to = game->pack_rank_file(rank, file); /* Rook from-square */ s = strstr(s, "with"); if (!s) continue; s+=4; while(isspace(*s)) s++; sscanf(s, "%c%d", &file, &rank); file -= 'a'; rank--; rfrom = game->pack_rank_file(rank, file); /* Calculate castle masks */ game->deduce_castle_flags(side, from, to, rfrom); continue; } if (strstr(line, "Symbol:") == line && pd) { s = line + 7; while (isspace(*s)) s++; char *p = strstr(s, "\""); if (!p) continue; p++; s = strstr(p, "\""); if (!s) continue; s++; s[-1] = '\0'; pd->abbr = strdup(p); p = strstr(s, "\""); if (!p) continue; p++; s = strstr(p, "\""); if (!s) continue; s++; s[-1] = '\0'; pd->symbol = strdup(p); continue; } if (strstr(line, "Promotion:") == line && pd) { s = line + 10; while (isspace(*s)) s++; char *p = strstr(s, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; npromotion_zone[WHITE] = zone[n].zone; break; } s = p; while (isspace(*s)) s++; p = strstr(s, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; npromotion_zone[BLACK] = zone[n].zone; break; } p = strstr(p, "\""); if(!p) continue; p++; s = strstr(p, "\""); if (s) s[0] = '\0'; pd->promotion = strdup(p); continue; } if (strstr(line, "Optional promotion:") == line && pd) { s = line + 19; while (isspace(*s)) s++; char *p = strstr(s, ","); if (!p) continue; p[0] = '\0'; p++; /* Find the corresponding zone */ for(int n=0; noptional_promotion_zone[WHITE] = zone[n].zone; break; } s = p; while (isspace(*s)) s++; p = strstr(s, ","); if (p) { p[0] = '\0'; p++; } /* Find the corresponding zone */ for(int n=0; noptional_promotion_zone[BLACK] = zone[n].zone; break; } pd->set_optional_promotion = true; if (p) { p = strstr(p, "\""); if(!p) continue; p++; s = strstr(p, "\""); if (s) s[0] = '\0'; if (!pd->promotion) pd->promotion = strdup(p); } continue; } if (strstr(line, "Demotion:") == line && pd) { s = line + 9; while (isspace(*s)) s++; char *p = s; p = strstr(p, "\""); if(!p) continue; p++; s = strstr(p, "\""); if (s) s[0] = '\0'; pd->demotion = strdup(p); continue; } if (strstr(line, "Flags:") == line && pd) { char *p; s = line + 6; while(isspace(*s)) s++; while((p = strtok(s, ","))) { s = NULL; while(isspace(*p)) p++; while(*p == ' ') p++; if (strstr(p, "royal") == p) { pd->flags |= PF_ROYAL; } else if (strstr(p, "castle") == p) { /* Ignore, deprecated */ } else if (strstr(p, "set_ep") == p) { pd->flags |= PF_SET_EP; } else if (strstr(p, "take_ep") == p) { pd->flags |= PF_TAKE_EP; } else if (strstr(p, "drop_no_check") == p) { pd->flags |= PF_DROPNOCHECK; } else if (strstr(p, "drop_no_mate") == p) { pd->flags |= PF_DROPNOMATE; } else if (strstr(p, "drop_one_file") == p) { pd->flags |= PF_DROPONEFILE; } else if (strstr(p, "drop_dead") == p) { pd->flags |= PF_DROPDEAD; } else if (strstr(p, "no_mate") == p) { pd->flags |= PF_NOMATE; } else if (strstr(p, "shak") == p) { pd->flags |= PF_SHAK; } } continue; } if (strstr(line, "Value:") == line && pd) { sscanf(line+6, "%d", &pd->value); continue; } if (strstr(line, "Max:") == line && pd) { if (strstr(line, ",")) sscanf(line+5, "%d,%d", &pd->max[0], &pd->max[1]); else { sscanf(line+5, "%d", &pd->max[0]); pd->max[1] = pd->max[0]; } continue; } if (strstr(line, "Rule:") == line) { s = line + 5; while(isspace(*s)) s++; if (strstr(s, "checkmate") == s) { if (strstr(s, "loss")) { game->mate_score = LEGALWIN; } else if (strstr(s, "win")) { game->mate_score = -LEGALWIN; } else if (strstr(s, "draw")) { game->mate_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->mate_score = ILLEGAL; } } if (strstr(s, "stalemate") == s) { if (strstr(s, "loss")) { game->stale_score = LEGALWIN; } else if (strstr(s, "win")) { game->stale_score = -LEGALWIN; } else if (strstr(s, "draw")) { game->stale_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->stale_score = ILLEGAL; } } if (strstr(s, "repeat") == s) { int count = -1; if (sscanf(s, "repeat%d", &count) == 1 && count >= 0) { game->repeat_claim = count-1; if (game->repeat_claim <= 0) game->repeat_claim = INT_MAX; if (strstr(s, "loss")) { game->rep_score = -LEGALWIN; } else if (strstr(s, "win")) { game->rep_score = LEGALWIN; } else if (strstr(s, "draw")) { game->rep_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->rep_score = -ILLEGAL; } } } if (strstr(s, "perpetual") == s) { if (strstr(s, "loss")) { game->perpetual = -LEGALWIN; } else if (strstr(s, "win")) { game->perpetual = LEGALWIN; } else if (strstr(s, "draw")) { game->perpetual = LEGALDRAW; } else if (strstr(s, "illegal")) { game->perpetual = -ILLEGAL; } else if (strstr(s, "repeat")) { game->perpetual = ILLEGAL+1; } } if (strstr(s, "loneking") == s) { if (strstr(s, "loss")) { game->bare_king_score = -LEGALWIN; } else if (strstr(s, "win")) { game->bare_king_score = LEGALWIN; } else if (strstr(s, "draw")) { game->bare_king_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->bare_king_score = ILLEGAL; } } if (strstr(s, "nopieces") == s) { if (strstr(s, "loss")) { game->no_piece_score = -LEGALWIN; } else if (strstr(s, "win")) { game->no_piece_score = LEGALWIN; } else if (strstr(s, "draw")) { game->no_piece_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->no_piece_score = ILLEGAL; } } if (strstr(s, "captureanyflag") == s) { game->board.rule_flags |= RF_CAPTURE_ANY_FLAG; if (strstr(s, "loss")) { game->flag_score = LEGALWIN; } else if (strstr(s, "win")) { game->flag_score = -LEGALWIN; } else if (strstr(s, "draw")) { game->flag_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->flag_score = ILLEGAL; } } if (strstr(s, "captureallflags") == s) { game->board.rule_flags |= RF_CAPTURE_ALL_FLAG; if (strstr(s, "loss")) { game->flag_score = LEGALWIN; } else if (strstr(s, "win")) { game->flag_score = -LEGALWIN; } else if (strstr(s, "draw")) { game->flag_score = LEGALDRAW; } else if (strstr(s, "illegal")) { game->flag_score = ILLEGAL; } } if (strstr(s, "taboo")) game->board.rule_flags |= RF_KING_TABOO; if (strstr(s, "keep capture")) game->board.rule_flags |= RF_KEEP_CAPTURE; if (strstr(s, "return capture")) game->board.rule_flags |= RF_RETURN_CAPTURE; if (strstr(s, "duplecheck")) game->board.rule_flags |= RF_KING_DUPLECHECK; if (strstr(s, "allow pickup")) game->board.rule_flags |= RF_ALLOW_PICKUP; if (strstr(s, "allow drop")) game->board.rule_flags |= RF_ALLOW_DROPS; if (strstr(s, "force drop")) game->board.rule_flags |= RF_FORCE_DROPS; if (strstr(s, "gate drop")) game->board.rule_flags |= RF_GATE_DROPS; if (strstr(s, "promote here")) game->board.rule_flags |= RF_PROMOTE_IN_PLACE; if (strstr(s, "promote drop")) game->board.rule_flags |= RF_PROMOTE_ON_DROP; if (strstr(s, "special init")) game->board.rule_flags |= RF_SPECIAL_IS_INIT; if (strstr(s, "bare rule")) game->board.rule_flags |= RF_USE_BARERULE; if (strstr(s, "chase rule")) game->board.rule_flags |= RF_USE_CHASERULE; if (strstr(s, "shak rule")) game->board.rule_flags |= RF_USE_SHAKMATE; } } /* Add the last remaining piece */ if (pd) { add_piece_to_game(game, pd); free(pd->name); free(pd->abbr); free(pd->symbol); free(pd->promotion); free(pd->demotion); free(pd); pd = NULL; } /* Free memory */ int n; for (n=0; nfinalise_variant(); return game; } game_t *create_game_from_file(const char *filename, const char *variant_name) { game_t *game = NULL; int files = 0; int ranks = 0; FILE *f; f = fopen(filename, "r"); if (!f) return game; char line[4096]; bool found_variant = false; while (!feof(f)) { if (fgets(line, sizeof line, f) == 0) continue; /* Strip away comments */ char *s = strstr(line, "#"); if (s) s[0] = '\0'; /* Snip end-of-line */ s = strstr(line, "\n"); if (s) s[0] = '\0'; /* Strip trailing space */ s = line+strlen(line)-1; while (s > line && isspace(s[0])) { s[0] = '\0'; s--; } /* New variant */ if (strstr(line, "Variant:") == line) { if (game) break; /* We're done loading the variant we're looking for */ if (strstr(line+8, variant_name)) { /* We've found the variant we're looking for */ found_variant = true; } continue; } /* Have we found the correct variant? */ if (!found_variant) continue; /* Set board size */ if (strstr(line, "Board:") == line) { s = line+6; sscanf(s, "%dx%d", &files, &ranks); /* Check whether the input is valid */ if (files > 16 || ranks > 16 || (files*ranks > 128)) { fclose(f); return NULL; } if (files * ranks <= 64) game = parse_game_description(f, variant_name, files, ranks); else game = parse_game_description(f, variant_name, files, ranks); break; } continue; } fclose(f); return game; } #endif SjaakII/include/xstring.h000644 000765 000024 00000000734 12465213742 016373 0ustar00eglebbkstaff000000 000000 #ifndef XSTRING_H #define XSTRING_H #include #include static inline char *trim(char *s) { char *p = s; while (*p && isspace(*p)) p++; if (p!= s) { for (size_t n = 0; n<=strlen(p); n++) s[n] = p[n]; } return s; } static inline char *chomp(char *s) { char *p; p = strstr(s, "\n"); if (p) *p = '\0'; return s; } static inline bool streq(const char *s1, const char *s2) { return strcmp(s1, s2) == 0; } #endif SjaakII/src/chess.cc000644 000765 000024 00000005223 12433144250 015272 0ustar00eglebbkstaff000000 000000 #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #include "bitboard.h" #include "board.h" #include "movegen.h" #include "aligned_malloc.h" #include "hashkey.h" #include "game.h" #include "variants.h" uint64_t perft(game_t *game, int depth, int root) { movelist_t movelist; side_t me = game->get_side_to_move(); uint64_t nodes = 0; int n; if (depth == 0) return 1; /* Check if previous move left the player in check */ game->generate_moves(&movelist); for (n=0; nplaymove(movelist.move[n]); if (!game->player_in_check(me)) /* Don't count illegal moves */ count = perft(game, depth-1, root - 1); nodes += count; if (root > 0) printf("%8s %10"PRIu64" %10"PRIu64"\n", move_to_string(movelist.move[n], NULL), count, nodes); game->takeback(); } return nodes; } #define streq(s1, s2) (strcmp((s1), (s2)) == 0) game_t *create_variant_game(const char *variant_name) { if (streq(variant_name, "normal")) { return create_standard_game(); } else if (streq(variant_name, "losalamos")) { return create_losalamos_game(); } else if (streq(variant_name, "micro")) { return create_micro_game(); } else if (streq(variant_name, "capablanca")) { return create_capablanca_game(); } else if (streq(variant_name, "create_pocketknight_game")) { return create_pocketknight_game(); } return NULL; } int main(void) { movelist_t movelist; initialise_hash_keys(); game_t *game = create_variant_game("normal"); if (!game) { printf("Could not create game object!\n"); exit(0); } game->start_new_game(); //game->setup_fen_position("rnbqkbnr/1pp1pppp/p7/3P4/8/8/PP1PPPPP/RNBQKBNR b KQkq -"); //game->setup_fen_position("rnbqkbnr/ppp1pppp/8/3P4/8/8/PP1PPPPP/RNBQKBNR b KQkq -"); uint64_t t = get_timer(); game->print_bitboards(); game->print_board(); game->generate_moves(&movelist); movelist.print(); //printf("%d\n", game->eval()); for (int n = 1; n<4+1; n++) { uint64_t nodes = perft(game, n, 0); uint64_t tt = get_timer(); if (tt == t) tt++; printf("%2d %10lld %5.2f %12.2fnps\n", n, (long long int)nodes, (double)(tt - t)/1000000.0,nodes*1.0e6/(tt-t)); t = tt; } exit(0); move_t move = movelist.move[0]; printf("%s\n", move_to_string(move)); game->playmove(move); game->print_bitboards(); game->takeback(); game->print_bitboards(); return 0; } SjaakII/src/eval/pst.cc000644 000765 000024 00000003456 12433144250 015730 0ustar00eglebbkstaff000000 000000 #include #include "pieces.h" #include "board.h" #include "pst.h" int psq_map[NUM_SIDES][128]; /* Base centralisation score for each square */ int centre_table[128]; /* Base advancement score for each square */ int advance_table[128]; /* Extra advancement score for proximity to promotion zone, for pawns */ int promo_table[128]; /* End game bonus for driving the defending king to the edge */ int lone_king_table[128]; /* Base shield score, for pawn shields */ int shield_table[128]; /* Initialise the base tables for the current board size */ void initialise_base_evaluation_tables(int files, int ranks) { int r, f; int c = files; if (ranks > c) c = ranks; int aa = 0; for (r = 0; r files/2+1 && (r == 1)) shield_table[s] = 1; lone_king_table[s] = 6*(abs(2*r - ranks + 1) + abs(2*f - files + 1)); psq_map[WHITE][s] = s; psq_map[BLACK][s] = f + (ranks-1 - r) * files; } } for (r = 0; r. */ #include #include #include "evalhash.h" #include "bool.h" /* FIXME: tune this */ #define NUM_BUCKETS 2 static inline size_t map_key_to_index(uint64_t key, size_t nelem) { return key & (nelem - 1); } static inline uint64_t map_key_to_lock(uint64_t key) { return key & ~0xffffll; } static int16_t extract_score(uint64_t data) { uint16_t uscore = data & 0xffff; return (int16_t)uscore; } eval_hash_table_t *create_eval_hash_table(size_t nelem) { eval_hash_table_t *table = calloc(1, sizeof *table); table->number_of_elements = nelem; table->data = calloc(nelem + NUM_BUCKETS, sizeof *table->data); return table; } void destroy_eval_hash_table(eval_hash_table_t *table) { if (table) { free(table->data); free(table); } } bool query_eval_table_entry(eval_hash_table_t *table, uint64_t key, int16_t *score) { size_t index, b; uint64_t lock; if (!table) return false; /* Map the key onto the array index, check if entry is there */ index = map_key_to_index(key, table->number_of_elements); lock = map_key_to_lock(key); //printf("0x%016llx 0x%016llx\n", key, lock); for (b=0; bdata[index + b].data; if (map_key_to_lock(data) == lock) { *score = extract_score(data); return true; } } return false; } void store_eval_hash_entry(eval_hash_table_t *table, uint64_t key, int16_t score) { size_t index, b; uint64_t lock, data; if (!table) return; /* Map the key onto the array index, check if entry is there */ index = map_key_to_index(key, table->number_of_elements); lock = map_key_to_lock(key); /* Find out where to store the entry. * If it already exists in one of the buckets we simply store it there * after moving the bucket to the start of the queue. * If it isn't present yet we shift the entire queue back one place and * create a new entry at the start. */ for (b = 0; bdata[index+b].data) == lock) { if (b) { eval_hash_t h = table->data[index]; table->data[index] = table->data[index+b]; table->data[index+b] = h; } goto store; } } /* If we made it here we need to create a new entry at the start of the * queue. */ for (b=NUM_BUCKETS-1; b>0; b--) table->data[index+b] = table->data[index+b-1]; store: data = lock | ((uint16_t)score); table->data[index].data = data; #ifdef DEBUG_EVHASH table->data[index].key = key; #endif } SjaakII/src/hash/hashkey.c000644 000765 000024 00000003456 12433144250 016407 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "hashkey.h" #include "genrand.h" uint64_t piece_key[MAX_PIECE_TYPES][2][128]; uint64_t hold_key[MAX_PIECE_TYPES][2][128]; uint64_t side_to_move_key; uint64_t flag_key[2][8]; uint64_t en_passant_key[128]; uint64_t genrand64(void) { return ((uint64_t)genrandui())<<32 | genrandui(); } void initialise_hash_keys(void) { int colour, piece, square; sgenrand(0x1422CE55); for (piece = 0; piece < MAX_PIECE_TYPES; piece++) for (colour = 0; colour<2; colour++) for (square = 0; square<128; square++) piece_key[piece][colour][square] = genrand64(); for (square = 0; square<128; square++) en_passant_key[square] = genrand64(); for (colour = 0; colour<2; colour++) for (square = 0; square<8; square++) flag_key[colour][square] = genrand64(); side_to_move_key = genrand64(); for (piece = 0; piece < MAX_PIECE_TYPES; piece++) for (colour = 0; colour<2; colour++) for (square = 0; square<128; square++) hold_key[piece][colour][square] = square ? genrand64() : 0; } SjaakII/src/hash/hashtable.c000644 000765 000024 00000010275 12452210627 016706 0ustar00eglebbkstaff000000 000000 /* Jazz, a program for playing chess * Copyright (C) 2009, 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "hashtable.h" #include "prefetch.h" #define HASH_BUCKETS 3 static inline size_t map_key_to_index(uint64_t key, size_t nelem) { return key & ( nelem - 1); } static inline uint32_t map_key_to_lock(uint64_t key) { return key >> 32; } hash_table_t *create_hash_table(size_t nelem) { hash_table_t *table; if (!nelem) return NULL; table = calloc(1, sizeof *table); table->data = calloc(nelem + HASH_BUCKETS, sizeof *table->data); table->number_of_elements = nelem; return table; } void destroy_hash_table(hash_table_t *table) { if (table) { free(table->data); free(table); } } /* Encrypt transposition table entry using the "xor trick" for lockless * hashing. */ static void crypt(hash_table_entry_t *hash) { uint64_t *h; assert(sizeof(hash_table_entry_t) == 3*sizeof(uint64_t)); h = (uint64_t *)hash; //h[1] ^= h[2]; h[0] ^= h[1]; } //static lock_t hash_lock = 0; void store_table_entry(hash_table_t *table, uint64_t key, int depth, int score, unsigned int flags, move_t best_move) { hash_table_entry_t *data; hash_table_entry_t *worst_data = NULL; size_t index, b; uint32_t lock; if (!table) return; /* Map the key onto the array index, check if entry is there */ index = map_key_to_index(key, table->number_of_elements); lock = map_key_to_lock(key); worst_data = data = table->data + index; //acquire_lock(&hash_lock); /* Check all buckets */ for (b=1; bdepth || hash.generation < table->generation || hash.generation == 0) { worst_data = data+b; } } data = worst_data; data->lock = lock; data->depth = depth; data->score = score; data->flags = flags; data->best_move = best_move; data->generation = table->generation; crypt(data); table->write_count++; //release_lock(&hash_lock); } bool retrieve_table(hash_table_t *table, uint64_t key, int *depth, int *score, unsigned int *flags, move_t *best_move) { size_t index, b; uint32_t lock; if (!table) return false; /* Map the key onto the array index, check if entry is there */ index = map_key_to_index(key, table->number_of_elements); lock = map_key_to_lock(key); //acquire_lock(&hash_lock); /* Check all buckets */ b = 0; for (b = 0; bdata[index+b]; crypt(&hash); if (hash.lock == lock) { hash.generation = table->generation; *depth = hash.depth; *score = hash.score; *flags = hash.flags; *best_move = hash.best_move; //release_lock(&hash_lock); return true; } } //release_lock(&hash_lock); return false; } void prepare_hashtable_search(hash_table_t *table) { table->generation++; table->write_count = 0; } void prefetch_hashtable(hash_table_t *table, uint64_t key) { size_t index; if (table) { index = map_key_to_index(key, table->number_of_elements); prefetch(table->data+index); } } int count_unused_table_entries(hash_table_t *table) { size_t n; int count; if (!table) return 0; count = 0; for (n=0; nnumber_of_elements; n++) { if (table->data[n].generation == 0) count++; } return count; } SjaakII/src/misc/aligned_malloc.c000644 000765 000024 00000002052 12452210627 017707 0ustar00eglebbkstaff000000 000000 #include #include #include "aligned_malloc.h" #include "assert.h" typedef struct { void *real_ptr; void *align_ptr; } aligned_memory_pool_t; static aligned_memory_pool_t *pool = NULL; static int pool_size = 0; static int pool_free = 0; /* Allocate aligned memory blocks. */ void *aligned_malloc(size_t size, size_t align) { uint8_t *real_ptr; void *align_ptr; assert((align & (align-1)) == 0); if (pool_free == pool_size) { pool_size = 2*(pool_size)+1; pool = realloc(pool, pool_size * sizeof *pool); } real_ptr = malloc(size + align-1); align_ptr = (void *) ((uint64_t)(real_ptr + align-1) & ~(align-1)); pool[pool_free].real_ptr = real_ptr; pool[pool_free].align_ptr = align_ptr; pool_free++; return align_ptr; } /* Free an aligned memory block */ void aligned_free(void *ptr) { int n; for (n=0; n * * This code is placed in the public domain. You are free to use it for any * purpose. If you add new platform support, please contribute a patch! * * Example use: * * char cfgdir[256]; * get_user_config_file(cfgdir, sizeof(cfgdir), "myapp"); * if (cfgdir[0] == 0) { * printf("Unable to find home directory.\n"); * return 1; * } * printf("Saving configuration file to %s\n", cfgdir); * * A number of constants are also defined: * * - MAX_PATH: Maximum length of a path, in characters. Used to allocate a * char array large enough to hold the returned path. * * - PATH_SEPARATOR_CHAR: The separator between folders. This will be either a * forward slash or a backslash depending on the platform. This is a * character constant. * * - PATH_SEPARATOR_STRING: The same as PATH_SEPARATOR_CHAR but as a C string, * to make it easier to append to other string constants. */ #ifdef __APPLE__ #define __unix__ #endif #if defined _MSC_VER # define _CRT_SECURE_NO_WARNINGS #endif #undef DATADIR #ifdef __unix__ #include #include #include #define MAX_PATH 512 /* arbitrary value */ #define PATH_SEPARATOR_CHAR '/' #define PATH_SEPARATOR_STRING "/" #elif defined(WIN32) #include /* MAX_PATH is defined by the Windows API */ #define PATH_SEPARATOR_CHAR '\\' #define PATH_SEPARATOR_STRING "\\" #else #error cfgpath.h functions have not been implemented for your platform! Please send patches. #endif /** Get an absolute path to a single configuration file, specific to this user. * * This function is useful for programs that need only a single configuration * file. The file is unique to the user account currently logged in. * * Output is typically: * * Windows: C:\Users\jcitizen\AppData\Roaming\appname.ini * unix: /home/jcitizen/.config/appname.conf * Mac: * * @param out * Buffer to write the path. On return will contain the path, or an empty * string on error. * * @param maxlen * Length of out. Must be >= MAX_PATH. * * @param appname * Short name of the application. Avoid using spaces or version numbers, and * use lowercase if possible. * * @post The file may or may not exist. * @post The folder holding the file is created if needed. */ void get_user_config_file(char *out, size_t maxlen, const char *appname) { #ifdef __unix__ const char *out_orig = out; char *home = getenv("XDG_CONFIG_HOME"); unsigned int config_len = 0; if (!home) { home = getenv("HOME"); if (!home) { // Can't find home directory out[0] = 0; return; } config_len = strlen(".config/"); } unsigned int home_len = strlen(home); unsigned int appname_len = strlen(appname); const int ext_len = strlen(".conf"); /* first +1 is "/", second is terminating null */ if (home_len + 1 + config_len + appname_len + ext_len + 1 > maxlen) { out[0] = 0; return; } memcpy(out, home, home_len); out += home_len; *out = '/'; out++; if (config_len) { memcpy(out, ".config/", config_len); out += config_len; /* Make the .config folder if it doesn't already exist */ mkdir(out_orig, 0755); } memcpy(out, appname, appname_len); out += appname_len; memcpy(out, ".conf", ext_len); out += ext_len; *out = 0; #elif defined(WIN32) unsigned int appname_len; if (maxlen < MAX_PATH) { out[0] = 0; return; } if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, out))) { out[0] = 0; return; } /* We don't try to create the AppData folder as it always exists already */ appname_len = (unsigned int)strlen(appname); if (strlen(out) + 1 + appname_len + strlen(".ini") + 1 > maxlen) { out[0] = 0; return; } strcat(out, "\\"); strcat(out, appname); strcat(out, ".ini"); #endif } /** Get an absolute path to a configuration folder, specific to this user. * * This function is useful for programs that need to store multiple * configuration files. The output is a folder (which may not exist and will * need to be created) suitable for storing a number of files. * * The returned path will always end in a platform-specific trailing slash, so * that a filename can simply be appended to the path. * * Output is typically: * * Windows: C:\Users\jcitizen\AppData\Roaming\appname\ * unix: /home/jcitizen/.config/appname/ * Mac: * * @param out * Buffer to write the path. On return will contain the path, or an empty * string on error. * * @param maxlen * Length of out. Must be >= MAX_PATH. * * @param appname * Short name of the application. Avoid using spaces or version numbers, and * use lowercase if possible. * * @post The folder is created if needed. */ void get_user_config_folder(char *out, size_t maxlen, const char *appname) { #ifdef __unix__ const char *out_orig = out; char *home = getenv("XDG_CONFIG_HOME"); unsigned int config_len = 0; if (!home) { home = getenv("HOME"); if (!home) { // Can't find home directory out[0] = 0; return; } config_len = strlen(".config/"); } unsigned int home_len = strlen(home); unsigned int appname_len = strlen(appname); /* first +1 is "/", second is trailing "/", third is terminating null */ if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) { out[0] = 0; return; } memcpy(out, home, home_len); out += home_len; *out = '/'; out++; if (config_len) { memcpy(out, ".config/", config_len); out += config_len; /* Make the .config folder if it doesn't already exist */ *out = '\0'; mkdir(out_orig, 0755); } memcpy(out, appname, appname_len); out += appname_len; /* Make the .config/appname folder if it doesn't already exist */ *out = '\0'; mkdir(out_orig, 0755); *out = '/'; out++; *out = 0; #elif defined(WIN32) unsigned int appname_len; if (maxlen < MAX_PATH) { out[0] = 0; return; } if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, out))) { out[0] = 0; return; } /* We don't try to create the AppData folder as it always exists already */ appname_len = (unsigned int)strlen(appname); if (strlen(out) + 1 + appname_len + 1 + 1 > maxlen) { out[0] = 0; return; } strcat(out, "\\"); strcat(out, appname); /* Make the AppData\appname folder if it doesn't already exist */ CreateDirectoryA(out, NULL); strcat(out, "\\"); #endif } /** Get an absolute path to a data storage folder, specific to this user. * * This function is useful for programs that need to store larger amounts of * data specific to each user. The output is a folder (which may not exist and * will need to be created) suitable for storing a number of data files. * * This path should be used for persistent, important data files the user would * want to keep. Do not use this path for temporary files, cache files, or * other files that can be recreated if they are deleted. Use * get_user_cache_folder() for those instead. * * The returned path will always end in a platform-specific trailing slash, so * that a filename can simply be appended to the path. * * Output is typically: * * Windows: C:\Users\jcitizen\AppData\Roaming\appname-data\ * unix: /home/jcitizen/.local/share/appname/ * Mac: * * @param out * Buffer to write the path. On return will contain the path, or an empty * string on error. * * @param maxlen * Length of out. Must be >= MAX_PATH. * * @param appname * Short name of the application. Avoid using spaces or version numbers, and * use lowercase if possible. * * @post The folder is created if needed. */ void get_user_data_folder(char *out, size_t maxlen, const char *appname) { #ifdef __unix__ const char *out_orig = out; char *home = getenv("XDG_DATA_HOME"); unsigned int config_len = 0; if (!home) { home = getenv("HOME"); if (!home) { // Can't find home directory out[0] = 0; return; } config_len = strlen(".local/share/"); } unsigned int home_len = strlen(home); unsigned int appname_len = strlen(appname); /* first +1 is "/", second is trailing "/", third is terminating null */ if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) { out[0] = 0; return; } memcpy(out, home, home_len); out += home_len; *out = '/'; out++; if (config_len) { memcpy(out, ".local/share/", config_len); out += config_len; /* Make the .local/share folder if it doesn't already exist */ *out = '\0'; mkdir(out_orig, 0755); } memcpy(out, appname, appname_len); out += appname_len; /* Make the .local/share/appname folder if it doesn't already exist */ *out = '\0'; mkdir(out_orig, 0755); *out = '/'; out++; *out = 0; #elif defined(WIN32) /* No distinction under Windows */ get_user_config_folder(out, maxlen, appname); #endif } /** Get an absolute path to a temporary storage folder, specific to this user. * * This function is useful for programs that temporarily need to store larger * amounts of data specific to each user. The output is a folder (which may * not exist and will need to be created) suitable for storing a number of * temporary files. The files may be lost or deleted when the program * terminates. * * This path should be used for temporary, unimportant data files that can * safely be deleted after the program terminates. Do not use this path for * any important files the user would want to keep. Use get_user_data_folder() * for those instead. * * The returned path will always end in a platform-specific trailing slash, so * that a filename can simply be appended to the path. * * Output is typically: * * Windows: C:\Users\jcitizen\AppData\Local\appname\ * unix: /home/jcitizen/.cache/appname/ * Mac: * * @param out * Buffer to write the path. On return will contain the path, or an empty * string on error. * * @param maxlen * Length of out. Must be >= MAX_PATH. * * @param appname * Short name of the application. Avoid using spaces or version numbers, and * use lowercase if possible. * * @post The folder is created if needed. */ void get_user_cache_folder(char *out, size_t maxlen, const char *appname) { #ifdef __unix__ const char *out_orig = out; char *home = getenv("XDG_CACHE_HOME"); unsigned int config_len = 0; if (!home) { home = getenv("HOME"); if (!home) { // Can't find home directory out[0] = 0; return; } config_len = strlen(".cache/"); } unsigned int home_len = strlen(home); unsigned int appname_len = strlen(appname); /* first +1 is "/", second is trailing "/", third is terminating null */ if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) { out[0] = 0; return; } memcpy(out, home, home_len); out += home_len; *out = '/'; out++; if (config_len) { memcpy(out, ".cache/", config_len); out += config_len; /* Make the .cache folder if it doesn't already exist */ *out = '\0'; mkdir(out_orig, 0755); } memcpy(out, appname, appname_len); out += appname_len; /* Make the .cache/appname folder if it doesn't already exist */ *out = '\0'; mkdir(out_orig, 0755); *out = '/'; out++; *out = 0; #elif defined(WIN32) unsigned int appname_len; if (maxlen < MAX_PATH) { out[0] = 0; return; } if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, out))) { out[0] = 0; return; } /* We don't try to create the AppData folder as it always exists already */ appname_len = (unsigned int)strlen(appname); if (strlen(out) + 1 + appname_len + 1 + 1 > maxlen) { out[0] = 0; return; } strcat(out, "\\"); strcat(out, appname); /* Make the AppData\appname folder if it doesn't already exist */ CreateDirectoryA(out, NULL); strcat(out, "\\"); #endif } SjaakII/src/misc/genrand.c000644 000765 000024 00000010347 12462364731 016410 0ustar00eglebbkstaff000000 000000 /* A C-program for MT19937: Integer version (1998/4/6) */ /* genrand() generates one pseudorandom unsigned integer (32bit) */ /* which is uniformly distributed among 0 to 2^32-1 for each */ /* call. sgenrand(seed) set initial values to the working area */ /* of 624 words. Before genrand(), sgenrand(seed) must be */ /* called once. (seed is any 32-bit integer except for 0). */ /* Coded by Takuji Nishimura, considering the suggestions by */ /* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ /* Modified by Evert Glebbeek 1999-2015 for use in his programs. */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public */ /* License as published by the Free Software Foundation; either */ /* version 2 of the License, or (at your option) any later */ /* version. */ /* This library 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 Library General Public License for more details. */ /* You should have received a copy of the GNU Library General */ /* Public License along with this library; if not, write to the */ /* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ /* 02111-1307 USA */ /* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ /* When you use this, send an email to: matumoto@math.keio.ac.jp */ /* with an appropriate reference to your work. */ /* REFERENCE */ /* M. Matsumoto and T. Nishimura, */ /* "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform */ /* Pseudo-Random Number Generator", */ /* ACM Transactions on Modeling and Computer Simulation, */ /* Vol. 8, No. 1, January 1998, pp 3--30. */ #include #include "genrand.h" /* Period parameters */ #define N 624 #define M 397 #define MATRIX_A 0x9908b0df /* constant vector a */ #define UPPER_MASK 0x80000000 /* most significant w-r bits */ #define LOWER_MASK 0x7fffffff /* least significant r bits */ /* Tempering parameters */ #define TEMPERING_MASK_B 0x9d2c5680 #define TEMPERING_MASK_C 0xefc60000 #define TEMPERING_SHIFT_U(y) (y >> 11) #define TEMPERING_SHIFT_S(y) (y << 7) #define TEMPERING_SHIFT_T(y) (y << 15) #define TEMPERING_SHIFT_L(y) (y >> 18) static unsigned int mt[N]; /* the array for the state vector */ static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ /* initializing the array with a NONZERO seed */ void sgenrand(unsigned int seed) { /* setting initial seeds to mt[N] using */ /* the generator Line 25 of Table 1 in */ /* [KNUTH 1981, The Art of Computer Programming */ /* Vol. 2 (2nd Ed.), pp102] */ mt[0]= seed & 0xffffffff; for (mti=1; mti= N) { /* generate N words at one time */ int kk; if (mti == N+1) /* if sgenrand() has not been called, */ sgenrand(4357); /* a default initial seed is used */ for (kk=0;kk> 1) ^ mag01[y & 0x1]; } for (;kk> 1) ^ mag01[y & 0x1]; } y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]; mti = 0; } y = mt[mti++]; y ^= TEMPERING_SHIFT_U(y); y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; y ^= TEMPERING_SHIFT_L(y); return y; } float genrandf(void) { return genrandui()/(float)UINT_MAX; } SjaakII/src/misc/keypressed.c000644 000765 000024 00000006013 12464136547 017147 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "bool.h" #include "keypressed.h" #if defined _WIN32 || defined _WIN64 #define WINDOWS #endif #if defined __unix__ || defined __APPLE__ #define UNIX #endif #ifdef WINDOWS #undef DATADIR #include #include #ifndef min #define min(x,y) ( ((x)<(y))?(x):(y) ) #endif #endif #ifdef UNIX #include #include #include #endif #if defined WINDOWS || defined UNIX const bool ponder_ok = true; #else const bool ponder_ok = false; #endif /* Determine whether there is input waiting in the standard input stream. * A variation of this code is present in at least OliThink, Beowulf, * Crafty and Stockfish. * This version adapted from Stockfish. */ bool keyboard_input_waiting(void) { #ifdef WINDOWS static bool virgin = true; static bool pipe = false; static HANDLE inh; DWORD dw; #if defined(FILE_CNT) if (stdin->_cnt > 0) return stdin->_cnt; #endif if (virgin) { virgin = false; 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 true; return dw; } else { INPUT_RECORD rec[256]; DWORD recCnt; DWORD i; // Count the number of unread input records, including keyboard, // mouse, and window-resizing input records. GetNumberOfConsoleInputEvents(inh, &dw); if (dw <= 0) return false; // Read data from console without removing it from the buffer if (!PeekConsoleInput(inh, rec, min(dw, 256), &recCnt)) return false; // Search for at least one keyboard event for (i = 0; i < recCnt; i++) if (rec[i].EventType == KEY_EVENT) return true; return false; } #elif defined UNIX struct timeval timeout; fd_set readfds; 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 #warning cannot determine keyboard output! return false; #endif } SjaakII/src/misc/snprintf.c000644 000765 000024 00000002135 12462364731 016631 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014, 2015 Evert Glebbeek * * This source file written by Martin Sedlak, modified by Evert Glebbeek. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if defined _MSC_VER # include "compilerdef.h" # include # include # include int snprintf(char *buf, size_t size, const char *fmt, ...) { int res; va_list ap; va_start(ap, fmt); res = vsnprintf(buf, size, fmt, ap); va_end(ap); return res; } #endif SjaakII/src/misc/softexp.c000644 000765 000024 00000003027 12452210627 016450 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "softexp.h" /* Stupid implementation of the exponential function. * First brings its argument in the range [0, 1] while collecting * appropriate integer powers of e, then uses the Pade approximation to * evaluate the exponential on the interval [0, 1]. * * Included here because for obscure reasons cross-compiled 64 bit Windows * binaries crash in Windows when the libc exp() function is called. */ double myexp(double x) { double x2, x3, x4; const double ee = 2.71828182845904523536028747135266250; double y = 1.; while (x > 1.) { y *= ee; x -= 1.0; } while (x < 0.) { y /= ee; x += 1.0; } x2 = x*x; x3 = x2*x; x4 = x2*x2; y *= (1. + 4./7.*x+1./7.*x2+2./105.*x3+1./840*x4) / (1 - 3./7.*x + 1./14. * x2 - 1/210.*x3); return y; } SjaakII/src/rules/bitboard.cc000644 000765 000024 00000004006 12433144250 017103 0ustar00eglebbkstaff000000 000000 #if 0 #include "bitboard.h" /* Specialisation for 64 bits: use optimised functions */ template<> inline int bitboard_t::popcount() const { return popcount64(bb); } template<> inline int bitboard_t::bitscan() const { return bitscan64(bb); } template<> inline int bitboard_t::popcount() const { return popcount128(bb); } template<> inline int bitboard_t::bitscan() const { return bitscan128(bb); } template<> inline bool bitboard_t::onebit() const { return onebit128(bb); } template<> inline bitboard_t bitboard_t::operator << (const int bits) const { return bitboard_t(shl128(bb, bits)); } template<> inline bitboard_t bitboard_t::operator >> (const int bits) const { return bitboard_t(shr128(bb, bits)); } template<> inline bool bitboard_t::test(int bit) const { return test128(bb, bit); } #ifndef __LP64__ template<> inline bitboard_t::bitboard_t() { bb = u128(0, 0); } template<> inline void bitboard_t::set(int bit) { if (bit < 64) bb |= u128(1ull < bit, 0); else bb |= u128(0, 1ull < (bit-64)); } template<> inline void bitboard_t::reset(int bit) { if (bit < 64) bb &= ~u128(1ull < bit, 0); else bb &= ~u128(0, 1ull < (bit-64)); } template<> inline bool bitboard_t::test(int bit) const { return test128(bb, bit); } template<> inline bool bitboard_t::is_empty() const { return is_zero128(bb); } template<> inline uint32_t bitboard_t::get_row(int row) const { typedef union { uint128_t i128; uint64_t i64[2]; } uuint128_t; uuint128_t b; b.i128 = shr128(bb, row * board_files); return b.i64[0] & rank_mask; } template<> inline uint32_t bitboard_t::get_file(int file) const { uint32_t file_bits = 0; int n; int bit = file; for (n=0; n #include "compilerdef.h" #include "game.h" static void printfstderr(const char *msg, ...) { static char buf[65536]; va_list ap; va_start(ap, msg); vsnprintf(buf, sizeof buf, msg, ap); va_end(ap); fprintf(stderr, "%s", buf); } void (*default_iteration_output)(const char *, ...) = NULL; void (*default_uci_output)(const char *, ...) = NULL; void (*default_xboard_output)(const char *, ...) = NULL; void (*default_error_output)(const char *, ...) = printfstderr; size_t default_hash_size = HASH_TABLE_SIZE; SjaakII/src/rules/move.cc000644 000765 000024 00000013054 12502304433 016264 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess variants * Copyright (C) 2011 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "compilerdef.h" #include "move.h" #include "squares.h" char piece_symbol_string[MAX_PIECE_TYPES+1]; char piece_psymbol_string[MAX_PIECE_TYPES+1]; char piece_drop_string[MAX_PIECE_TYPES+1]; const char *move_to_lan_string(move_t move, bool castle_san, bool castle_kxr, char *buffer) { static char static_buffer[64]; char *s = static_buffer; char dash = '-'; if (buffer) s = buffer; s[0] = '\0'; const char *p = ""; if (is_promotion_move(move) || is_gate_move(move)) { p = piece_symbol_string + get_move_promotion_piece(move); if (piece_symbol_string[get_move_piece(move)] == '+') p = "+"; } if (get_move_from(move) == get_move_to(move)) { snprintf(s, sizeof static_buffer, "@@@@"); return s; } if (is_castle_move(move)) { int from = get_move_from(move); int to = get_move_to(move); if (castle_san) { if (unpack_file(to) >= div_file) snprintf(s, sizeof static_buffer, "%s", kingside_castle); else snprintf(s, sizeof static_buffer, "%s", queenside_castle); } else if (castle_kxr) { snprintf(s, sizeof static_buffer, "%s%s%c", square_names[from], square_names[get_castle_move_from2(move)], tolower(*p)); } else { snprintf(s, sizeof static_buffer, "%s%s%c", square_names[from], square_names[to], tolower(*p)); } if (is_gate_move(move)) { if (get_move_drop_square(move) != from) { snprintf(s, sizeof static_buffer, "%s%s%c", square_names[get_castle_move_from2(move)], square_names[from], tolower(*p)); } else { snprintf(s, sizeof static_buffer, "%s%s%c", square_names[from], square_names[to], tolower(*p)); } } return s; } else if (is_drop_move(move)) { snprintf(s, sizeof static_buffer, "%c@%s", piece_drop_string[get_move_piece(move)], square_names[get_move_to(move)]); /* Promotion drop? */ uint16_t h = get_move_holding(move); int piece = decode_holding_piece(h); if (piece != get_move_piece(move)) { p = piece_symbol_string + get_move_piece(move); snprintf(s, sizeof static_buffer, "%c@%s%c", piece_drop_string[piece], square_names[get_move_to(move)], tolower(*p)); } } else if (is_pickup_move(move)) //snprintf(s, sizeof static_buffer, "%c^%s", piece_drop_string[get_move_piece(move)], square_names[get_move_from(move)]); snprintf(s, sizeof static_buffer, "@@%s", square_names[get_move_from(move)]); else snprintf(s, sizeof static_buffer, "%s%s%c", square_names[get_move_from(move)], square_names[get_move_to(move)], tolower(*p)); if (is_gate_move(move)) snprintf(s + strlen(s), sizeof static_buffer-strlen(s), "%c", tolower(*p)); return s; } const char *move_to_string(move_t move, char *buffer) { static char static_buffer[256]; char *s = static_buffer; char dash = '-'; if (buffer) s = buffer; s[0] = '\0'; int n = 0; /* In normal chess (and Capablanca), "O-O" is king-side castling, "O-O-O" is queen-side. * This holds true in FRC and CRC games, but it is not true in Janus chess. * This is a problem, because simply testing whether the king starts out on the left-side of the board * would break FRC/CRC variants. */ if (is_castle_move(move)) { int to = unpack_file(get_move_to(move)); if (to >= div_file) snprintf(s, 256, "%s", kingside_castle); else snprintf(s, 256, "%s", queenside_castle); if (is_gate_move(move)) { snprintf(s + strlen(s), 256-strlen(s), "/%c%s", piece_symbol_string[get_move_promotion_piece(move)], square_names[get_move_drop_square(move)]); } return s; } int p = get_move_piece(move); if (is_drop_move(move)) { int to = get_move_to(move); char fp = piece_symbol_string[p]; snprintf(s, 256, "%c@%s", fp, square_names[to]); return s; } if (is_pickup_move(move)) { int from = get_move_from(move); char fp = piece_symbol_string[p]; snprintf(s, 256, "%c^%s", fp, square_names[from]); return s; } /* Normal move or capture */ if (is_capture_move(move)) dash = 'x'; int from, to; char fp = '\0', tp = '\0'; if (is_promotion_move(move)) tp = piece_symbol_string[get_move_promotion_piece(move)]; from = get_move_from(move); to = get_move_to(move); fp = piece_symbol_string[p]; snprintf(s, 256, "%c%s%c%s%c", fp, square_names[from], dash, square_names[to], tp); if (fp == '+') { if (tp) tp = '+'; snprintf(s, 256, "%c%c%s%c%s%c", fp, piece_psymbol_string[p], square_names[from], dash, square_names[to], tp); } if (is_gate_move(move)) snprintf(s + strlen(s), 256-strlen(s), "/%c", piece_symbol_string[get_move_promotion_piece(move)]); return s; } SjaakII/src/rules/san.cc000644 000765 000024 00000006324 12502304433 016101 0ustar00eglebbkstaff000000 000000 #include #include "san.h" #include "squares.h" #include "compilerdef.h" const char *move_to_short_string(move_t move, const movelist_t *movelist, char *buffer) { static char static_buffer[256]; char *s = buffer; const char *gate_token = ""; const char *token = ""; const char *origin = ""; char piece = ' '; char tp = '\0'; if (!s) s = static_buffer; if (move == 0) { snprintf(s, sizeof static_buffer, "(pass)"); return s; } int from = get_move_from(move); int to = get_move_to(move); int p = get_move_piece(move); if (is_castle_move(move)) { int f = unpack_file(to); if (f >= div_file) snprintf(s, sizeof static_buffer, "%s", kingside_castle); else snprintf(s, sizeof static_buffer, "%s", queenside_castle); if (is_gate_move(move)) { snprintf(s + strlen(s), 256-strlen(s), "/%c%s", piece_symbol_string[get_move_promotion_piece(move)], square_names[get_move_drop_square(move)]); } return s; } if (is_capture_move(move)) token = "x"; if (is_drop_move(move)) token = "@"; if (is_promotion_move(move) || is_gate_move(move)) tp = piece_symbol_string[get_move_promotion_piece(move)]; if (is_gate_move(move)) gate_token = "/"; piece = piece_symbol_string[p]; if (is_drop_move(move)) piece = piece_drop_string[p]; if (is_pickup_move(move)) { piece = piece_drop_string[p]; token = "^"; to = from; goto disambiguous; } if (is_drop_move(move)) goto disambiguous; /* Slightly special case: pawn capture */ if (piece == ' ' && is_capture_move(move)) { origin = file_names[unpack_file(from)]; } else if (p && movelist) { /* The information we have now might be ambiguous - check */ int count = 0; int n; for (n=0; nnum_moves; n++) { if (is_drop_move(movelist->move[n])) continue; if (get_move_piece(move) == get_move_piece(movelist->move[n]) && to == get_move_to(movelist->move[n])) { if (is_promotion_move(move) && is_promotion_move(movelist->move[n])) count += tp == piece_symbol_string[get_move_promotion_piece(movelist->move[n])]; else if (!is_promotion_move(move) && !is_promotion_move(movelist->move[n])) count++; } } if (count <= 1) goto disambiguous; /* Try to disambiguate by file */ count = 0; for (n=0; nnum_moves; n++) { if (is_drop_move(movelist->move[n])) continue; if (get_move_piece(move) == get_move_piece(movelist->move[n]) && to == get_move_to(movelist->move[n]) && unpack_file(from) == unpack_file(get_move_from(movelist->move[n]))) count++; } if (count == 1) { origin = file_names[unpack_file(from)]; } else if (count > 1) { /* Disambiguate by row */ origin = rank_names[unpack_rank(from)]; } } disambiguous: snprintf(s, 15, "%c%s%s%s%s%c", piece, origin, token, square_names[to], gate_token, tp); if (piece == '+') { if (tp) tp = '+'; snprintf(s, 15, "%c%c%s%s%s%s%c", piece, piece_psymbol_string[p], origin, token, square_names[to], gate_token, tp); } return s; } SjaakII/src/rules/squares.cc000644 000765 000024 00000006377 12465213742 017025 0ustar00eglebbkstaff000000 000000 #include #include #include #include #include "compilerdef.h" #include "squares.h" char *square_names[128] = { NULL }; char *file_names[16] = { NULL }; char *rank_names[16] = { NULL }; uint8_t packed_file_rank[128]; int rank_offset = 1; const char *kingside_castle; const char *queenside_castle; static bool virgin = true; int div_file = 0; bool keep_labels = false; static int board_files = 0; static int board_ranks = 0; void initialise_square_names(int files, int ranks) { board_files = files; board_ranks = ranks; /* Initialise square names and file/rank masks */ for (int n=0; n<128; n++) { if (!virgin) free(square_names[n]); square_names[n] = NULL; } for (int n=0; n<16; n++) { if (!virgin) { free(rank_names[n]); free(file_names[n]); } rank_names[n] = NULL; file_names[n] = NULL; } virgin = false; for (int f=0; f #include "bitboard.h" #include "board.h" #include "movegen.h" #include "aligned_malloc.h" #include "game.h" int main(void) { game_template_t *game = new game_template_t; bitboard_t large(u128(1,0)); bitboard_t bb((uint64_t)0x06ll); bitboard_t b(3); bitboard_t b2; bitboard_t b3; bitboard_t tiny(0); bitboard_t::initialise_bitboards(4,4); bitboard_t::initialise_bitboards(4,4); bitboard_t::initialise_bitboards(11,11); movegen_t::initialise(); movegen_t::initialise(); movegen_t::initialise(); movegen_t::initialise_slider_tables(); movegen_t::initialise_slider_tables(); movegen_t::initialise_slider_tables(); movegen_t::initialise_super_tables(); movegen_t::initialise_super_tables(); movegen_t::initialise_super_tables(); game->set_board_size(8,8); //large = large << 16; move_flag_t fb = movegen_t::define_piece_move("slide (A,D)"); move_flag_t fr = movegen_t::define_piece_move("slide (H,V)"); move_flag_t fq = fb | fr; move_flag_t fn = movegen_t::define_piece_move("leap (1,2)"); move_flag_t fk = movegen_t::define_piece_move("leap (1,0)|(1,1)"); bitboard_t pz[2]; game->add_piece_type(fn, fn, 0, pz, "", "Knight", "N,n", "N"); game->add_piece_type(fb, fb, 0, pz, "", "Bishop", "B,b", "B"); game->add_piece_type(fr, fr, 0, pz, "", "Rook", "R,r", "R"); game->add_piece_type(fq, fq, 0, pz, "", "Queen", "Q,q", "Q"); game->add_piece_type(fk, fk, 0, pz, "", "King", "K,k", "K"); movegen_t::initialise_super_tables(); movegen_t::deduce_castle_flags(WHITE, 4, 6, 7); movegen_t::deduce_castle_flags(WHITE, 4, 2, 0); movegen_t::deduce_castle_flags(BLACK, 60, 62, 63); movegen_t::deduce_castle_flags(BLACK, 60, 58, 56); b2 = b << 1; printf("%d %d %d\n", large.onebit(), large.popcount(), large.bitscan()); printf("%d %d %d\n", bb.onebit(), bb.popcount(), bb.bitscan()); printf("%d %d %d %d\n", b.onebit(), b.popcount(), b.bitscan(), b.test(4)); printf("%d %d %d %d\n", b2.onebit(), b2.popcount(), b2.bitscan(), b2.test(4)); b2 = b2 >> 1; printf("%d\n", b2 == b); printf("%d %d %d\n", b3.onebit(), b3.popcount(), b3.bitscan()); printf("0x%016llx\n", bitboard_t::board_light.value()); for (int n = 0; n<8; n++) printf("%08x\n", large.get_rank(n)); printf("\n"); for (int n = 0; n<8; n++) printf("%08x\n", large.get_file(n)); #if 0 uint32_t occ = (1<<1)|(1<<2); int where = 0; large = u128(occ, 0); tiny ^= tiny; printf("\n"); for (int n = 0; n movegen; printf("\n"); for (int n = 0; n occb; occb.set(0); occb.set(3); occb.set(2*8); occb.set(14); occb.set(36); occb.set(36 + 2*9); occb.set(36 - 7); occb.set(36 + 2*7); bitboard_t moves = movegen_t::generate_slider_move_bitboard(MF_SLIDER_H|MF_SLIDER_V, WHITE, 0, occb); bitboard_t dmoves = movegen_t::generate_hopper_move_bitboard(MF_HOPPER_D|MF_HOPPER_A, WHITE, 36, occb); printf("\nOccupied:\n"); occb.print(); printf("\n"); moves.print(); printf("\n"); dmoves.print(); printf("%08x\n", fr); printf("%08x\n", fk); printf("%d\n", get_leaper_index(fk)); movegen_t::super[36].print(); bitboard_t knightm = movegen_t::generate_leaper_move_bitboard(fn, WHITE, 36, occb); printf("\n"); movegen_t::leaper[get_leaper_index(fk)][0].print(); printf("\n"); movegen_t::leaper[get_leaper_index(fk)][36].print(); printf("\n"); knightm.print(); //printf("\n"); //occb.fill_north().print(); //printf("\n"); //occb.fill_south().print(); #if 0 for (to = 0; to < tiny.board_ranks*tiny.board_files; to++) { printf("\n"); for (int n = 0; n. */ #if defined _MSC_VER # define USE_GETTICKCOUNT # include # undef min #else # include # if defined HAVE_CLOCK_GETTIME && defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L && defined _POSIX_TIMERS && _POSIX_TIMERS>0 && defined _POSIX_MONOTONIC_CLOCK # define USE_CLOCK_GETTIME # include # else # include # endif #endif #include #include #include "assert.h" #include "timer.h" #include "keypressed.h" /* returns the current value of the counter, in micro seconds */ uint64_t get_timer(void) { #ifdef USE_CLOCK_GETTIME struct timespec t; clock_gettime(0, &t); return t.tv_sec*1000000 + t.tv_nsec/1000; #elif defined USE_GETTICKCOUNT return (uint64_t)GetTickCount() * 1000; #else struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000000 + t.tv_usec; #endif } static int min(int x, int y) { return (xstart_time = get_timer(); clock->extra_time = 0; } /* Get the time elapsed since the last call to start_clock(), in ms */ int peek_timer(const chess_clock_t *clock) { return (int)((get_timer() - clock->start_time) / 1000); } /* Calculate time allocated for this a move */ int get_chess_clock_time_for_move(const chess_clock_t *clock) { int num_moves = clock->movestogo; int time_for_move; if (clock->pondering) { if (!keyboard_input_waiting()) return INT_MAX; else return 0; } if (clock->time_per_move) return clock->time_per_move; if (clock->check_clock == NULL) return INT_MAX; /* No set number of moves to be played within the time limit, make some * sort of estimate for how many moves we may want to play in the time * remaining. */ if (num_moves == 0) { if (clock->root_moves_played < 20) num_moves = 15+clock->root_moves_played; else num_moves = 20; } if (num_moves < 0) num_moves = 10; /* Base time for this move: the total time left divided by the number of * moves. */ time_for_move = clock->time_left/num_moves; /* We want to preserve a small buffer to avoid time losses */ if (num_moves < 5) time_for_move = (int)(time_for_move*0.95); /* Adjust: we can spare at least half the increment */ if (clock->time_left > clock->time_inc/2) time_for_move += clock->time_inc/2; /* We may have allocated some extra time for this move, for instance * because our best move failed low. */ time_for_move += min(clock->extra_time, clock->time_left); /* If we're short on time and have an increment, then play quickly so we * gain some extra time to finish the game. */ if (clock->time_left < clock->time_inc * 5) time_for_move = 3*clock->time_inc/4; return min(time_for_move, clock->time_left - clock->time_left/8); } /* Time management: check if a fixed time per move has passed since the * clock was started. */ static bool check_time_per_move_clock(const chess_clock_t *clock) { int time_passed = peek_timer(clock); if (time_passed >= clock->time_per_move) return true; return false; } static bool check_time_for_game(const chess_clock_t *clock) { int time_passed = peek_timer(clock); int time_for_move = get_chess_clock_time_for_move(clock); /* If we've expended our time for this move, then abort */ if (time_passed >= time_for_move) return true; return false; } static bool check_keyboard(const chess_clock_t *clock) { return keyboard_input_waiting(); } void set_time_per_move(chess_clock_t *clock, int msec) { clock->time_per_move = msec; clock->check_clock = check_time_per_move_clock; } void set_ponder_timer(chess_clock_t *clock) { clock->check_clock = check_keyboard; } void set_infinite_time(chess_clock_t *clock) { clock->check_clock = NULL; } void set_time_for_game(chess_clock_t *clock) { clock->time_per_move = 0; clock->check_clock = check_time_for_game; } SjaakII/src/xboard.cc000644 000765 000024 00000354423 12502304433 015453 0ustar00eglebbkstaff000000 000000 /* Sjaak, a program for playing chess * Copyright (C) 2011, 2014 Evert Glebbeek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #if defined _MSC_VER # include #endif #include "sjaak.h" #include "xstring.h" #include "keypressed.h" #include "cfgpath.h" #include "test_suite.h" #ifdef __APPLE__ #define __unix__ #endif #ifdef __unix__ #include #include #endif #ifdef HAVE_READLINE #include #include #endif #if defined __LP64__ || defined _WIN64 #define ARCHSTR "(x86_64)" #elif defined __i386__ || defined _WIN32 #define ARCHSTR "(i386)" #elif defined POWERPC #define ARCHSTR "(powerpc)" #else #define ARCHSTR "(unknown)" #endif #ifndef SJAAKIIVERSION #define SJAAKIIVERSION "(version unknown) " #endif #define VERSIONSTR SJAAKIIVERSION #ifdef DEBUGMODE #undef VERSIONSTR #define VERSIONSTR SJAAKIIVERSION " (debug)" #endif #define PROGNAME "Sjaak II" #define TIME_BUFFER 100 typedef struct help_topic_t { const char *topic; const char *cmd; const char *text; } help_topic_t; typedef struct position_signature_t { const char *fen; int depth; uint64_t nodes; } position_signature_t; static position_signature_t perftests[] = { // Martin Sedlak's test positions // (http://www.talkchess.com/forum/viewtopic.php?t=47318) // avoid illegal ep { "3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1", 6, 1134888 }, { "8/8/8/8/k1p4R/8/3P4/3K4 w - - 0 1", 6, 1134888 }, { "8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1", 6, 1015133 }, { "8/b2p2k1/8/2P5/8/4K3/8/8 b - - 0 1", 6, 1015133 }, // en passant capture checks opponent: { "8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1", 6, 1440467 }, { "8/5k2/8/2Pp4/2B5/1K6/8/8 w - d6 0 1", 6, 1440467 }, // short castling gives check: { "5k2/8/8/8/8/8/8/4K2R w K - 0 1", 6, 661072 }, { "4k2r/8/8/8/8/8/8/5K2 b k - 0 1", 6, 661072 }, // long castling gives check: { "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1", 6, 803711 }, { "r3k3/8/8/8/8/8/8/3K4 b q - 0 1", 6, 803711 }, // castling (including losing cr due to rook capture): { "r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1", 4, 1274206 }, { "r3k2r/7b/8/8/8/8/1B4BQ/R3K2R b KQkq - 0 1", 4, 1274206 }, // castling prevented: { "r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1", 4, 1720476 }, { "r3k2r/8/5Q2/8/8/3q4/8/R3K2R w KQkq - 0 1", 4, 1720476 }, // promote out of check: { "2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1", 6, 3821001 }, { "3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1", 6, 3821001 }, // discovered check: { "8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1", 5, 1004658 }, { "5K2/8/1Q6/2N5/8/1p2k3/8/8 w - - 0 1", 5, 1004658 }, // promote to give check: { "4k3/1P6/8/8/8/8/K7/8 w - - 0 1", 6, 217342 }, { "8/k7/8/8/8/8/1p6/4K3 b - - 0 1", 6, 217342 }, // underpromote to check: { "8/P1k5/K7/8/8/8/8/8 w - - 0 1", 6, 92683 }, { "8/8/8/8/8/k7/p1K5/8 b - - 0 1", 6, 92683 }, // self stalemate: { "K1k5/8/P7/8/8/8/8/8 w - - 0 1", 6, 2217 }, { "8/8/8/8/8/p7/8/k1K5 b - - 0 1", 6, 2217 }, // stalemate/checkmate: { "8/k1P5/8/1K6/8/8/8/8 w - - 0 1", 7, 567584 }, { "8/8/8/8/1k6/8/K1p5/8 b - - 0 1", 7, 567584 }, // double check: { "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1", 4, 23527 }, { "8/5k2/8/5N2/5Q2/2K5/8/8 w - - 0 1", 4, 23527 }, // short castling impossible although the rook never moved away from its corner { "1k6/1b6/8/8/7R/8/8/4K2R b K - 0 1", 5, 1063513 }, { "4k2r/8/8/7r/8/8/1B6/1K6 w k - 0 1", 5, 1063513 }, // long castling impossible although the rook never moved away from its corner { "1k6/8/8/8/R7/1n6/8/R3K3 b Q - 0 1", 5, 346695 }, { "r3k3/8/1N6/r7/8/8/8/1K6 w q - 0 1", 5, 346695 }, // From the Wiki { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -", 4, 4085603 }, { "rnbqkb1r/pp1p1ppp/2p5/4P3/2B5/8/PPP1NnPP/RNBQK2R w KQkq - 0 6", 3, 53392 }, // Shortened form of the third position below { "8/7p/p5pb/4k3/P1pPn3/8/P5PP/1rB2RK1 b - d3 0 28", 4, 67197 }, // Some FRC postions by Reinhard Scharnagl // (http://www.talkchess.com/forum/viewtopic.php?t=55274) // We have each of them twice, to get the number of moves at the root // correct too. { "r1k1r2q/p1ppp1pp/8/8/8/8/P1PPP1PP/R1K1R2Q w KQkq - 0 1", 1, 23 }, { "r1k2r1q/p1ppp1pp/8/8/8/8/P1PPP1PP/R1K2R1Q w KQkq - 0 1", 1, 28 }, { "8/8/8/4B2b/6nN/8/5P2/2R1K2k w Q - 0 1", 1, 34 }, { "2r5/8/8/8/8/8/6PP/k2KR3 w K - 0 1", 1, 17 }, { "4r3/3k4/8/8/8/8/6PP/qR1K1R2 w KQ - 0 1", 1, 19 }, { "r1k1r2q/p1ppp1pp/8/8/8/8/P1PPP1PP/R1K1R2Q w KQkq - 0 1", 2, 522 }, { "r1k2r1q/p1ppp1pp/8/8/8/8/P1PPP1PP/R1K2R1Q w KQkq - 0 1", 2, 738 }, { "8/8/8/4B2b/6nN/8/5P2/2R1K2k w Q - 0 1", 2, 318 }, { "2r5/8/8/8/8/8/6PP/k2KR3 w K - 0 1", 2, 242 }, { "4r3/3k4/8/8/8/8/6PP/qR1K1R2 w KQ - 0 1", 2, 628 }, { "r1k1r2q/p1ppp1pp/8/8/8/8/P1PPP1PP/R1K1R2Q w KQkq - 0 1", 5, 7096972 }, { "r1k2r1q/p1ppp1pp/8/8/8/8/P1PPP1PP/R1K2R1Q w KQkq - 0 1", 5, 15194841 }, { "8/8/8/4B2b/6nN/8/5P2/2R1K2k w Q - 0 1", 5, 3223406 }, { "2r5/8/8/8/8/8/6PP/k2KR3 w K - 0 1", 5, 985298 }, { "4r3/3k4/8/8/8/8/6PP/qR1K1R2 w KQ - 0 1", 5, 8992652 }, // John Merlino's test positions, some of these take a long time, only do them // in debug mode. #ifdef DEBUGMODE { "r3k2r/8/8/8/3pPp2/8/8/R3K1RR b KQkq e3 0 1", 6, 485647607 }, { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 6, 706045033 }, { "8/7p/p5pb/4k3/P1pPn3/8/P5PP/1rB2RK1 b - d3 0 28", 6, 38633283 }, { "8/3K4/2p5/p2b2r1/5k2/8/8/1q6 b - - 1 67", 7, 493407574 }, { "rnbqkb1r/ppppp1pp/7n/4Pp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3", 6, 244063299 }, { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -", 5, 193690690 }, { "8/p7/8/1P6/K1k3p1/6P1/7P/8 w - -", 8, 8103790 }, { "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - -", 6, 71179139 }, { "r3k2r/p6p/8/B7/1pp1p3/3b4/P6P/R3K2R w KQkq -", 6, 77054993 }, { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", 7, 178633661 }, { "8/5p2/8/2k3P1/p3K3/8/1P6/8 b - -", 8, 64451405 }, { "r3k2r/pb3p2/5npp/n2p4/1p1PPB2/6P1/P2N1PBP/R3K2R w KQkq -", 5, 29179893 }, #endif { NULL, 0, 0 } }; /* Test positions, for Spartan chess */ static position_signature_t spartan_perftests[] = { { "5Q1k/8/7K/8/8/8/5h2/8 b - -", 5, 53727 }, { "k7/g6k/1c6/7K/2B1Q3/8/8/1R6 b - - 34 75", 5, 6293168 }, { "lgkcckw1/hhhhhhhh/8/8/3l4/5P2/PPPPPKPP/RNBQ1BNR w KQ - 3 3", 5, 1190857 }, { "1R1k1w2/h5kh/h1g1B2h/3c3h/3Q1PN1/8/2P3PP/R6K b - - 0 1", 5, 23939987 }, { "3k4/2h1k2h/5Q2/2hR4/3h4/8/PP3P1P/3w1K2 b - 0 7", 5, 3195587 }, { "4k2R/4hk2/2c2hh1/h3gh2/3h4/1B3P2/PP3P1P/2R2K2 b - 0 7", 5, 6440892 }, { "3k4/2h2k1R/5Q2/g4h2/3h4/8/PP3P1P/3w1K2 b - 1 6", 5, 8066536 }, { NULL, 0, 0 } }; /* Test positions, for Shogi */ static position_signature_t shogi_perftests[] = { { "8l/1l+R2P3/p2pBG1pp/kps1p4/Nn1P2G2/P1P1P2PP/1PS6/1KSG3+r1/LN2+p3L [Sbgnppp] b 0 62", 3, 2552846 }, { "lnsgkgsnl/1r5b1/pppppp1pp/6p2/9/2P6/PP1PPPPPP/1B5R1/LNSGKGSNL [-] w 0 1", 4, 2000286 }, { "l6+Rl/3s1s3/p4p1pp/1G1G2p2/1p3kBN1/4P1P2/PP+p2R1PP/4KS3/1+b6L[PPPNNSppnlgg] b 1 47", 1, 5 }, { NULL, 0, 0 } }; /* Test positions, for Xiangqi */ static position_signature_t xiangqi_perftests[] = { { "rheakaehr/9/1c7/p1p1p1p1p/7c1/4C4/P1P1P1P1P/1C7/9/RHEAKAEHR b - 4 2", 4, 411539 }, { "2e1ka1h1/2P1h1HC1/9/p3pc3/8p/9/4P2c1/4E4/9/2EAKA3 b 2 26", 2, 60 }, { "rheakaehr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RHEAKAEHR w - - 0 1", 5, 133312995 }, { NULL, 0, 0 } }; /* Test positions, for Seirawan */ static position_signature_t seirawan_perftests[] = { { "Q3k2r/2qnbppp/1ppppn2/5bB1/3P4/2N1PN2/PP2BPPP/R3K2R [HEhe] b KQBCFGkcdfg - 0 2", 1, 5 }, { "rQbqkbnr/p1pppppp/8/8/2p5/8/PP1PPPPP/RNB1KBNR [HEhe] b KQBCFGkqcdfg - 0 3", 1, 30 }, { "6k1/5ppp/1p6/1P6/4e3/8/rb1BKPbP/1R6 [-] w - - 8 1", 4, 97954 }, { "1h1qkber/rQ1bp1pp/3p1n2/2pP2N1/p7/P3B3/1PP2PPP/RE2KBHR [-] w KQk - 1 16", 4, 1966909 }, { NULL, 0, 0 } }; /* Test positions, for Sittuyin */ static position_signature_t sittuyin_perftests[] = { { "8/6k1/6p1/3s2P1/3npR2/2r5/p2N2F1/3K4[-] b 0 49", 4, 357804 }, { "8/5R2/2P5/5S2/3sFs2/P3k3/2K5/8 w 3 69", 4, 61959 }, { NULL, 0, 0 } }; /* Benchmark positions. For now we just use the Stockfish ones */ static position_signature_t benchtests[] = { { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 0, 0 }, { "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -", 0, 0 }, { "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", 0, 0 }, { "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", 0, 0 }, { "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14", 0, 0 }, { "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14", 0, 0 }, { "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15", 0, 0 }, { "r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13", 0, 0 }, { "r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16", 0, 0 }, { "4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17", 0, 0 }, { "2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11", 0, 0 }, { "r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16", 0, 0 }, { "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22", 0, 0 }, { "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18", 0, 0 }, { "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22", 0, 0 }, { "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26", 0, 0 }, { NULL, 0, 0 } }; static help_topic_t help_topic[] = { /* .........|.........|.........|.........|.........|.........|.........|.........| */ { "all", NULL, NULL }, { "analyse", "analyse, analyze", " Analyse the current position.\n" }, { "bench", "test benchmark [depth]", " Perform a benchmark test to the specified depth. The returned node-count\n" " can be used as a validation that the program is working correctly while\n" " the reported time can be used as a performance measure on the current\n" " system.\n" }, { "board", "board [on|off]", " Print the current board position, or toggles automatic printing of the\n" " current position on and off.\n" }, { "book", "book [filename|off]", " Set the name of the (polyglot) opening book file to use.\n" " 'book off' switches off the opening book.\n" }, #ifdef SMP { "cores", "cores N, threads N", " Use N cores/threads for the search.\n" }, #endif { "fen", NULL, " Print the FEN representation of the current board position.\n" }, { "force", NULL, " Switch to 'force' mode: Sjaak will play neither side in the game until\n" " it receives a 'go' command\n" }, { "go", NULL, " Switch off force mode, tell Sjaak to start playing from the current position.\n" }, { "help", "help [topic]", " Display a list of help topics, or detailed information about a particular\n" " topic.\n" }, { "hint", NULL, " Print the move that Sjaak is pondering on. If there is no ponder move, no\n" " hint is displayed.\n" }, { "level", "level moves time inc", " Set time control options: number of moves per session, time per session\n" " (either in minutes or minutes:seconds) and time increment (in seconds)\n" }, { "load", "load filename", " Load variant descriptions from the specified file\n" }, { "maxnodes", "maxnodes n", " Set the maximum number of nodes that can be searched before a move is\n" " returned. Setting maxnodes to 0 disables it and restores normal time\n" " control.\n" }, { "memory", "memory [MB]", " Set the (approximate) amount of memory the program can use, in MB. The\n" " actual amount of memory used will be different from this and may be\n" " slightly larger or smaller.\n" }, { "new", NULL, " Start a new game from the starting position.\n" " In xboard mode the current variant is reset to 'normal'.\n" }, { "perft", "perft [depth] [print depth]", " Perform a 'perft' (performance test) on the current position: count all\n" " positions that can result from this position to the specified depth.\n" " If 'print depth' is specified then the total will be sub-divided per move\n" " upto 'print depth'\n" }, { "ponder", "ponder [on|off]", " Switches ponder mode on or off (Sjaak will think while it is not on move)\n" }, { "post", "(no)post, post off", " Display thinking output (post) or not (nopost/post off)\n" }, { "prompt", "prompt [on|off]", " Switch the prompt on or off\n" }, { "quit", "quit, exit, bye", " Exit Sjaak\n" }, { "readepd", "readepd filename", " Read (and setup) a position from an EPD file.\n" }, { "rules", NULL, " Summarise the rules of the game and the movement of the pieces in human-radable text.\n" }, { "setboard", "setboard FEN", " Setup a position on the board from a FEN string.\n" }, { "sd", "sd depth", " Specify the maximum search depth\n" }, { "settings", NULL, " Show current settings\n" }, { "shell", "!command", " Run a shell command.\n" }, { "st", "st time", " Specify the maximum time (in seconds) to think on a single move\n" }, { "takeback", "takeback, remove", " Reverses the last two moves in the game, if any.\n" }, { "test", "test [movegen|benchmark [depth]]", " Perform tests on the move generator, or the search.\n" }, { "time", "time csec", " Set the remaining time on the engine's clock, in centi-seconds.\n" }, { "ucci", "ucci [on|off]", " Toggle UCCI mode on or off. In UCCI mode commands from the UCCI protocol\n" " are recognised in addition to the standard commands described here.\n" " 'ucci' is equivalent to 'ucci on'\n"}, { "uci", "uci [on|off]", " Toggle UCI mode on or off. In UCI mode commands from the UCI protocol\n" " are recognised in addition to the standard commands described here.\n" " 'uci' is equivalent to 'uci on'\n"}, { "undo", NULL, " Unmakes the last move in the game, if any. If it is Sjaak's turn, it will\n" " start thinking again immediately.\n" }, { "unload", "unload filename", " Unload variant descriptions from the specified file\n" }, { "usi", "usi [on|off]", " Toggle USI mode on or off. In USI mode commands from the USI protocol\n" " are recognised in addition to the standard commands described here.\n" " 'usi' is equivalent to 'usi on'\n"}, { "variant", "variant name", " Set the name of the variant that will be selected when a new game is started.\n" " If no name is specified a list of known variants is displayed.\n" }, { "variants", NULL, " List all known variants.\n" }, { "xboard", "xboard [on|off]", " Switch to xboard mode: prompt off, don't display board, don't print SAN\n" " moves, don't trap interrupts (ctrl-C).\n" " 'xboard' is equivalent to 'xboard on'\n" }, { "MOVE", NULL, " Play a move on the board. Moves can be entered as 'long algebraic'\n" " (e2e4, g1f3) or SAN (e4, Nf3).\n" }, { NULL, NULL, NULL } }; static int option_ms = MATE_SEARCH_ENABLE_DROP; static int draw_count = 0; static int resign_count = 0; static eval_t draw_threshold = 0; static eval_t resign_threshold = -500; static bool user_variants_first = true; static bool mask_dark_squares = false; static bool send_piece_descriptions = true; static bool report_fail_low = false; static bool report_fail_high = false; static bool repetition_claim = true; static bool prompt = true; static bool show_board = true; static bool san = true; static bool trapint = true; static int tc_moves = 40; static int tc_time = 60000; static int tc_inc = 0; static char configfile[1024] = { 0 }; static char *fairy_file = NULL; static char deferred[256]; #ifdef __APPLE__ #define __unix__ #endif #ifdef __unix__ static sig_t old_signal_handler; void interrupt_computer(int i) { abort_search = true; if (old_signal_handler) old_signal_handler(i); } #endif #ifdef HAVE_READLINE static bool stdin_is_terminal(void) { #ifdef __unix__ return isatty(fileno(stdin)); #else return true; #endif } #endif static FILE *f = NULL; static char *buf; static bool may_ponder = false; static bool in_play = true; static void log_engine_output(const char *msg, ...) ATTRIBUTE_UNUSED; static void log_engine_output(const char *msg, ...) { va_list ap; va_start(ap, msg); vsnprintf(buf, 65535, msg, ap); va_end(ap); if (f) { fprintf(f, " %s", buf); fflush(f); } } static void log_xboard_output(const char *msg, ...) { va_list ap; static bool newline = true; va_start(ap, msg); vsnprintf(buf, 65535, msg, ap); va_end(ap); if (f) { if (newline) fprintf(f, "> "); newline = false; fprintf(f, "%s", buf); if (strstr(buf, "\n")) newline = true; } printf("%s", buf); } struct variant_file_list_t { const char *filename; const char *shortname; const char *longname; int files, ranks; size_t line_number; }; static variant_file_list_t *custom_variants = NULL; static int num_custom_variants = 0; static int max_custom_variants = 0; static variant_file_list_t *new_variant_file_entry(void) { variant_file_list_t *file = NULL; if (num_custom_variants >= max_custom_variants) { max_custom_variants = max_custom_variants + 8; custom_variants = (variant_file_list_t *)realloc(custom_variants, max_custom_variants*sizeof *custom_variants); } file = custom_variants + num_custom_variants; num_custom_variants++; return file; } static void invalidate_variant_file(const char *filename) { if (!filename) return; /* Skip if the file has already been indexed. * TODO: we need a way to invalidate a previously scanned file. */ for (int n=0; n 0; n++) { if (!streq(custom_variants[n].filename, filename)) continue; free((void *)custom_variants[n].filename); free((void *)custom_variants[n].shortname); free((void *)custom_variants[n].longname); custom_variants[n].filename = NULL; custom_variants[n].shortname = NULL; custom_variants[n].longname = NULL; custom_variants[n] = custom_variants[num_custom_variants-1]; n--; num_custom_variants--; } } static void scan_variant_file(const char *filename) { /* Skip if the file has already been indexed. * TODO: we need a way to invalidate a previously scanned file. */ for (int n=0; n line && isspace(s[0])) { s[0] = '\0'; s--; } /* New variant */ if (strstr(line, "Variant:") == line) { s = line + 8; while (isspace(*s)) s++; free((void *)name); name = strdup(s); continue; } if (strstr(line, "Board:") == line) { variant_file_list_t *file = new_variant_file_entry(); int files, ranks; sscanf(line + 6, "%dx%d", &files, &ranks); file->filename = strdup(filename); file->longname = strdup(name); file->files = files; file->ranks = ranks; file->line_number = line_number; char *s = strdup(name); file->shortname = s; /* Truncate the long name into something XBoard can handle */ while (*s) { *s = tolower(*s); if (isspace(*s)) *s = '_'; if (!isalnum(s[1])) { if (!isspace(s[1])) s[1] = 0; if (*s == '_') *s = 0; } s++; } } line_number++; } free((void *)name); //for (int n = 0; nmove_string_to_move(s); if (move == 0) { //fprintf(stderr, "\n"); if (f) { fprintf(f, "Report illegal move %s in position:\n", move_str); //print_bitboards_file(f, game->board); } return false; } game->playmove(move); } else { return false; } return true; } static void send_legal_move_targets(game_t *game, int from, const movelist_t *external_movelist = NULL) { char fen[4096]; int move_board[256]; if (!game) return; memset(move_board, 0, sizeof move_board); movelist_t movelist; /* First, generate the list of moves for this position */ if (external_movelist) { movelist.clear(); for(int n = 0; nnum_moves; n++) movelist.push(external_movelist->move[n]); } else { game->generate_legal_moves(&movelist); } move_t move; while ((move = movelist.next_move())) { if (get_move_from(move) != from) continue; int s = game->bit_to_square[get_move_to(move)]; if (s < 0) continue; if (move_board[s] == 3) continue; if (is_promotion_move(move)) move_board[s] = 3; else if (is_capture_move(move)) move_board[s] = 2; else move_board[s] = 1; } int n = 0; int ranks = (game->virtual_ranks > 0) ? game->virtual_ranks : game->ranks; int files = (game->virtual_files > 0) ? game->virtual_files : game->files; for (int r = ranks-1; r>=0; r--) { int count = 0; for (int f = 0; f < files; f++) { int s = f + r * files; /* Empty? */ if (move_board[s] == 0) { count++; continue; } /* Not empty, do we have a count? */ if (count) n += snprintf(fen+n, 4096 - n, "%d", count); count = 0; const char *colour_string = " YRM"; n += snprintf(fen+n, 4096-n, "%c", colour_string[move_board[s]]); } if (count) n += snprintf(fen+n, 4096 - n, "%d", count); if (r) n += snprintf(fen+n, 4096 - n, "/"); } log_xboard_output("highlight %s\n", fen); } /* Play a sequence of moves from the initial position */ void replay_game(game_t *game, char *moves) { movelist_t movelist; char *s; /* First rewind to the beginning if not there yet */ while (game->moves_played) game->takeback(); s = moves; while(s && *s) { char move_str[10] = { 0 }; while (*s == ' ') s++; for (int n = 0; n<10; n++) { if (*s == ' ' || *s == 0) break; move_str[n] = *s; s++; } bool result = input_move(game, move_str); if (!result) { fprintf(stderr, "Bad move %s in movelist!\n", move_str); break; } } } static void set_time_from_string(game_t *game, const char *timestr) { float milliseconds; sscanf(timestr, "%g", &milliseconds); milliseconds *= 10; /* Reserve a bit of time for when we reach the time control, so we don't get penalised by a time * loss. We don't need this for a Fischer clock. */ if (milliseconds > TIME_BUFFER) milliseconds -= TIME_BUFFER; game->clock.time_left = milliseconds; game->move_clock[game->moves_played] = game->clock.time_left; set_time_for_game(&game->clock); } static void set_timecontrol_from_string(game_t *game, const char *tcstr) { int moves, milliseconds; float minutes, seconds, inc; /* Set defaults */ set_time_per_move(&game->clock, 5000); game->clock.movestotc = 0; game->clock.movestogo = 0; game->clock.time_inc = 0; if (strstr(tcstr, ":")) { sscanf(tcstr, "%d %g:%g %g", &moves, &minutes, &seconds, &inc); } else { sscanf(tcstr, "%d %g %g", &moves, &minutes, &inc); seconds = 0; } seconds += minutes*60; milliseconds = seconds * 1000; /* Reserve a bit of time for when we reach the time control, so we don't get penalised by a time * loss. We don't need this for a Fischer clock. */ if (inc == 0 && milliseconds > TIME_BUFFER) milliseconds -= TIME_BUFFER; game->clock.movestotc = moves; game->clock.movestogo = moves; game->clock.time_inc = inc*1000; game->clock.time_left = milliseconds; game->move_clock[game->moves_played] = game->clock.time_left; set_time_for_game(&game->clock); tc_moves = game->clock.movestotc; tc_time = game->clock.time_left; tc_inc = game->clock.time_inc; } static bool interrupt_ponder(game_t *) { return keyboard_input_waiting(); } static bool keyboard_input_on_move(game_t *game) { if (deferred[0]) return true; if (abort_search) return true; static char ponder_input[65536]; bool input_waiting = keyboard_input_waiting(); bool read_input = input_waiting && fgets(ponder_input, sizeof ponder_input, stdin); if (read_input) { chomp(ponder_input); trim(ponder_input); if (strstr(ponder_input, "random")) { sgenrand((unsigned int)time(NULL)); game->random_ok = true; } else if (strstr(ponder_input, "easy")) { may_ponder = false; } else if (strstr(ponder_input, "hard")) { may_ponder = true; } else if (strstr(ponder_input, "nopost") || strstr(ponder_input, "post off") == ponder_input) { game->set_xboard_output_function(NULL); } else if (strstr(ponder_input, "post")) { game->set_xboard_output_function(log_xboard_output); } else if (strstr(ponder_input, "?") == ponder_input) { return true; } else if (strstr(ponder_input, "stop") == ponder_input) { return true; } else if (strstr(ponder_input, "draw")) { if (game->draw_count > draw_count) log_xboard_output("offer draw\n"); } else if (strstr(ponder_input, "new")) { snprintf(deferred, sizeof deferred, "%s", ponder_input); return true; } else if (strstr(ponder_input, "otim")) { } else if (strstr(ponder_input, "ping")) { log_xboard_output("pong %s\n", ponder_input+5); } else if (strstr(ponder_input, "result")) { return true; } else if (strstr(ponder_input, "time")) { set_time_from_string(game, ponder_input+5); } else if (strstr(ponder_input, "level") == ponder_input) { set_timecontrol_from_string(game, ponder_input+6); } else if (strstr(ponder_input, "st ")) { float tpm = 5; sscanf(ponder_input+3, "%g", &tpm); int time_per_move = tpm * 1000; set_time_per_move(&game->clock, time_per_move); } else if (strstr(ponder_input, "force") == ponder_input) { in_play = false; } else if (strstr(ponder_input, "pause")) { uint64_t start_pause = get_timer(); /* Sleep until keyboard input */ while(!fgets(ponder_input, sizeof ponder_input, stdin) || !strstr(ponder_input, "resume")); uint64_t stop_pause = get_timer(); game->clock.start_time += stop_pause - start_pause; } else if (streq(ponder_input, "quit")) { if (game) delete game; free(buf); exit(0); } else { snprintf(deferred, sizeof deferred, "%s", ponder_input); } } return false; } static bool (*uci_clock_handler)(const struct chess_clock_t *clock); static bool uci_keyboard_input_on_ponder(game_t *game) { if (!game->pondering) return true; static char ponder_input[65536]; if (keyboard_input_waiting() && fgets(ponder_input, sizeof ponder_input, stdin)) { if (f) { fprintf(f, "< %s\n", ponder_input); fflush(f); } if (strstr(ponder_input, "ponderhit")) { game->clock.check_clock = uci_clock_handler; game->pondering = false; game->check_keyboard = NULL; return false; } else if (strstr(ponder_input, "isready") == ponder_input) { log_xboard_output("readyok\n"); return false; } else if (strstr(ponder_input, "stop") == ponder_input) { game->pondering = false; return true; } else if (streq(ponder_input, "quit")) { if (game) delete game; free(buf); exit(0); } } return false; } static bool keyboard_input_analyse(game_t *game) { static char ponder_input[65536]; bool restart = false; if (game->analyse_move != 0) return true; if (!game->analysing) return false; if (keyboard_input_waiting() && fgets(ponder_input, sizeof ponder_input, stdin)) { chomp(ponder_input); trim(ponder_input); if (strstr(ponder_input, "undo")) { if (game->analyse_moves_played) { game->analyse_undo++; restart = true; } } else if (strstr(ponder_input, "new")) { game->analyse_new = true; restart = true; } else if (strstr(ponder_input, "exit")) { game->analysing = false; restart = true; } else if (strstr(ponder_input, "setboard")) { char *p = strstr(ponder_input, " "); while (p && *p && p[0]==' ') p++; free((void *)game->analyse_fen); game->analyse_fen = strdup(p); restart = true; } else if (strstr(ponder_input, ".") == ponder_input) { } else if (strstr(ponder_input, "hint")) { } else if (strstr(ponder_input, "bk")) { } else if (streq(ponder_input, "quit")) { if (game) delete game; free(buf); exit(0); } else if (strstr(ponder_input, "lift")) { for (int square = 0; square < game->ranks*game->files; square++) { if (streq(ponder_input+5, square_names[square])) { send_legal_move_targets(game, square, &game->analyse_movelist); break; } } } else if (strstr(ponder_input, "put")) { /* No action required */ } else if (strstr(ponder_input, "hover")) { /* TODO */ } else { char *s = ponder_input; if(s && *s) { move_t move = game->move_string_to_move(s, &game->analyse_movelist); game->analyse_move = move; if (move == 0) log_xboard_output("Illegal move: %s\n", ponder_input); else restart = true; } } } return restart; } static uint64_t perft(game_t *game, int depth, int root, bool legal = false) { movelist_t *movelist = game->movelist + depth; side_t me = game->get_side_to_move(); uint64_t nodes = 0; int n; if (depth == 0) return 1; /* Check if previous move left the player in check */ if (legal) game->generate_legal_moves(movelist); else game->generate_moves(movelist); for (n=0; nnum_moves; n++) { uint64_t count = 0; game->playmove(movelist->move[n]); if (legal || !game->player_in_check(me)) { /* Don't count illegal moves */ game->test_move_game_check(); count = perft(game, depth-1, root - 1); } nodes += count; if (root > 0) printf("%8s %10"PRIu64" %10"PRIu64"\n", move_to_string(movelist->move[n], NULL), count, nodes); game->takeback(); if (abort_search) break; } return nodes; } static bool run_movegen_test(const char *name, const char *variant, const position_signature_t *suite, bool legal) { game_t *game = NULL; int n = 0; while (suite[n].fen) { uint64_t nodes; game = create_variant_game(variant); game->start_new_game(); game->setup_fen_position(suite[n].fen); printf("."); fflush(stdout); nodes = perft(game, suite[n].depth, 0, legal); if (nodes != suite[n].nodes) { printf("\n"); printf("*** Failed at %s position %d (%s):\n", name, n, suite[n].fen); printf(" Expected %"PRIu64" nodes at depth %d, got %"PRIu64" nodes\n", suite[n].nodes, suite[n].depth, nodes); return false; } delete game; n++; } return true; } static void test_movegen(bool legal = false) { if (!run_movegen_test("Chess", "normal", perftests, legal)) return; if (!run_movegen_test("Spartan", "spartan", spartan_perftests, legal)) return; if (!run_movegen_test("Shogi", "shogi", shogi_perftests, legal)) return; if (!run_movegen_test("XiangQi", "xiangqi", xiangqi_perftests, legal)) return; if (!run_movegen_test("Seirawan", "seirawan", seirawan_perftests, legal)) return; if (!run_movegen_test("Sittuyin", "sittuyin", sittuyin_perftests, legal)) return; printf("\nOk.\n"); } static uint64_t test_benchmark(int depth) { game_t *game = NULL; int n = 0; uint64_t nodes = 0; uint64_t t = get_timer(); unsigned long long int nodes_searched = 0; #ifdef TRACK_PRUNING_STATISTICS memset(branches_pruned_by_move, 0, sizeof branches_pruned_by_move); #endif while (benchtests[n].fen) { game = create_variant_game("normal"); game->start_new_game(); game->random_ok = false; game->output_iteration = NULL; game->uci_output = NULL; game->xboard_output = NULL; //printf("%s\n", benchtests[n].fen); game->setup_fen_position(benchtests[n].fen); printf("."); fflush(stdout); #ifdef __unix__ if (trapint) old_signal_handler = signal(SIGINT, interrupt_computer); #endif game->think(depth); #ifdef __unix__ if (trapint) signal(SIGINT, old_signal_handler); #endif nodes_searched = game->clock.nodes_searched; delete game; if (abort_search) { printf("\n*** Aborted"); break; } //printf("%"PRIu64"\n", nodes); nodes += nodes_searched; n++; } uint64_t tt = get_timer(); printf("\n"); printf("%"PRIu64" nodes searched\n", nodes); printf("Elapsed time %"PRIu64" ms\n", (tt - t) / 1000); printf("%g nodes / s\n", 1.0e6*nodes / (tt - t)); return (tt - t); } #ifdef SMP /* Test the SMP search. * Test position is the first from Hyatt (1994), after White's 9th move in a game * Mchess Pro - Cray Blitz. */ static void test_smp(int cores, int depth) { game_t *game = NULL; int n = get_number_of_threads(); uint64_t t_start[2]; uint64_t t_end[2]; unsigned long long int moves_searched[2]; char *fen = "r2qkbnr/ppp2p1p/2n5/3P4/2BP1pb1/2N2p2/PPPQ2PP/R1B2RK1/ b - - 2 9";//benchtests[1].fen; init_threads(1); game = create_variant_game("normal") game->start_new_game(); game->random_ok = false; setup_fen_position(game, fen); print_board(game->board); printf("Single core analysis:\n"); t_start[0] = get_timer(); computer_play(game, depth); t_end[0] = get_timer(); moves_searched[0] = game->moves_searched; end_game(game); init_threads(cores); printf("Analysis using %d cores:\n", cores); game = create_variant_game("normal") game->start_new_game(); game->random_ok = false; setup_fen_position(game, fen); t_start[1] = get_timer(); computer_play(game, depth); t_end[1] = get_timer(); moves_searched[1] = game->moves_searched; end_game(game); init_threads(n); printf("\n"); printf("Single core: %-10"PRIu64" nodes searched\n", moves_searched[0]); printf("Multi-core: %-10"PRIu64" nodes searched\n", moves_searched[1]); printf("Single core time %"PRIu64" ms\n", (t_end[0]-t_start[0]) / 1000); printf("Multi-core time %"PRIu64" ms\n", (t_end[1]-t_start[1]) / 1000); printf("Relative node counts (multi/single): %.2f\n", (float)moves_searched[1] / moves_searched[0]); printf("Parallel speed-up (time-to-depth): %.2f\n", (float)(t_end[0]-t_start[0]) / (t_end[1]-t_start[1])); } #endif static void run_test_suite(uint64_t time, const char *tests[]) { movelist_t legal_moves; movelist_t best_moves; int n = 0; int position_searched = 0; int position_correct = 0; int score = 0; int max_positions = 0; while (tests[max_positions]) max_positions++; while (tests[n]) { const char *best_move_string = strstr(tests[n], "bm "); if (!best_move_string) { n++; continue; } best_move_string += 3; position_searched++; printf("(%d/%d) %s:\n", position_searched, max_positions, tests[n]); game_t *game = create_variant_game("normal"); game->start_new_game(); game->setup_fen_position(tests[n]); game->generate_legal_moves(&legal_moves); best_moves.clear(); const char *move_score_string = strstr(tests[n], "c0"); if (move_score_string == NULL || strstr(move_score_string, "=") == NULL) { const char *s = best_move_string; while (*s && *s != ';') { char move_str[32] = { 0 }; char *p = move_str; while (*s && isspace(*s)) s++; while (*s && !isspace(*s) && *s != ';') { if (*s != '+') { *p = *s; p++; } s++; } move_t move = game->move_string_to_move(move_str, &legal_moves); if (move) { best_moves.push(move); best_moves.score[best_moves.num_moves-1] = 10; } } } else { const char *s = move_score_string + 4; while (*s && *s != ';') { char move_str[32] = { 0 }; int score = 10; char *p = move_str; while (*s && isspace(*s)) s++; while (*s && !isspace(*s) && *s != '=') { if (*s != '+') { *p = *s; p++; } s++; } if (*s == '=') { s++; sscanf(s, "%d", &score); while (*s && !isspace(*s)) s++; } move_t move = game->move_string_to_move(move_str, &legal_moves); if (move) { best_moves.push(move); best_moves.score[best_moves.num_moves-1] = score; } } } set_time_per_move(&game->clock, (int)time); game->think(MAX_SEARCH_DEPTH); move_t move = game->get_last_move(); //printf("%s\n", move_to_string(move)); //best_moves.print(); bool correct = false; for (int k=0; krep_score == LEGALDRAW) log_xboard_output("1/2-1/2 {%d-fold repetition}\n", game->repeat_claim+1); else { side_t me = game->get_side_to_move(); if (game->player_in_check(me)) { if (game->rep_score < 0) { if (game->get_side_to_move() == BLACK) log_xboard_output("0-1 {White chases}\n"); else log_xboard_output("1-0 {Black chases}\n"); } else { if (game->get_side_to_move() == BLACK) log_xboard_output("1-0 {White chases}\n"); else log_xboard_output("0-1 {Black chases}\n"); } } else { if (game->rep_score < 0) { if (game->get_side_to_move() == WHITE) log_xboard_output("0-1 {Black chases}\n"); else log_xboard_output("1-0 {White chases}\n"); } else { if (game->get_side_to_move() == WHITE) log_xboard_output("1-0 {Black chases}\n"); else log_xboard_output("0-1 {White chases}\n"); } } } break; case SEARCH_GAME_ENDED_MATE: if (game->get_side_to_move() == WHITE) log_xboard_output("0-1 {Black mates}\n"); else log_xboard_output("1-0 {White mates}\n"); break; case SEARCH_GAME_ENDED_LOSEBARE: if (game->get_side_to_move() == WHITE) log_xboard_output("0-1 {Bare king}\n"); else log_xboard_output("1-0 {Bare king}\n"); break; case SEARCH_GAME_ENDED_WINBARE: if (game->get_side_to_move() == WHITE) log_xboard_output("1-0 {Bare king}\n"); else log_xboard_output("0-1 {Bare king}\n"); break; case SEARCH_GAME_ENDED_STALEMATE: if (game->stale_score == 0) log_xboard_output("1/2-1/2 {Stalemate}\n"); else if (game->stale_score < 0) { if (game->get_side_to_move() == WHITE) log_xboard_output("0-1 {Black mates}\n"); else log_xboard_output("1-0 {White mates}\n"); } else { if (game->get_side_to_move() == WHITE) log_xboard_output("1-0 {Stalemate}\n"); else log_xboard_output("0-1 {Stalemate}\n"); } break; case SEARCH_GAME_ENDED_INSUFFICIENT: log_xboard_output("1/2-1/2 {insufficient material}\n"); break; case SEARCH_GAME_ENDED_FORFEIT: log_xboard_output("Illegal move (may not be used to give mate): %s\n", input); game->takeback(); //if (game->get_side_to_move() == WHITE) // log_xboard_output("1-0 {Black forfeits}\n"); //else // log_xboard_output("0-1 {White forfeits}\n"); break; case SEARCH_GAME_ENDED_INADEQUATEMATE: log_xboard_output("1/2-1/2 {Mate, but no shak}\n"); break; case SEARCH_GAME_ENDED_FLAG_CAPTURED: if (game->flag_score == 0) log_xboard_output("1/2-1/2 {Flag captured}\n"); else if (game->flag_score < 0) { if (game->side_captured_flag(BLACK)) log_xboard_output("0-1 {Black captures the flag}\n"); else log_xboard_output("1-0 {White captures the flag}\n"); } else { if (game->side_captured_flag(BLACK)) log_xboard_output("1-0 {Black captures the flag}\n"); else log_xboard_output("0-1 {White captures the flag}\n"); } break; case SEARCH_GAME_ENDED_NOPIECES: if (game->no_piece_score == 0) { log_xboard_output("1/2-1/2 {No pieces remaining}\n"); } else if (game->flag_score < 0) { if (game->get_side_to_move() == WHITE) log_xboard_output("0-1 {No white pieces remaining}\n"); else log_xboard_output("1-0 {No black pieces remaining}\n"); } else { if (game->get_side_to_move() == WHITE) log_xboard_output("1-0 {No white pieces remaining}\n"); else log_xboard_output("0-1 {No black pieces remaining}\n"); } break; case SEARCH_GAME_ENDED: log_xboard_output("telluser game ended (unknown reason)\n"); break; } } static void read_config_file(FILE *cf) { static char buf[65536]; while (!feof(cf)) { if (fgets(buf, sizeof buf, cf) == 0) continue; char *eol = strstr(buf, "\n"); if (eol) *eol = 0; if (strstr(buf, "user_alias") == buf) { char *s = strchr(buf, '='); if (s) { s++; while (*s && isspace(*s)) s++; if (*s) { free(user_alias); user_alias = strdup(s); } } } else if (strstr(buf, "fairy_file") == buf) { char *s = strchr(buf, '='); if (s) { s++; while (*s && isspace(*s)) s++; if (*s) { free(fairy_file); fairy_file = strdup(s); } } } else if (strstr(buf, "option_mate_search") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); if (i < MATE_SEARCH_DISABLED) i = MATE_SEARCH_DISABLED; if (i > MATE_SEARCH_ENABLED) i = MATE_SEARCH_ENABLED; option_ms = i; } } else if (strstr(buf, "user_variants_first") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); user_variants_first = i != 0; } } else if (strstr(buf, "mask_dark_squares") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); mask_dark_squares = i != 0; } } else if (strstr(buf, "send_piece_descriptions") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); send_piece_descriptions = i != 0; } } else if (strstr(buf, "report_fail_low") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); report_fail_low = i != 0; } } else if (strstr(buf, "report_fail_high") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); report_fail_high = i != 0; } } else if (strstr(buf, "repetition_claim") == buf) { char *s = strchr(buf, '='); if (s) { int i = 1; s++; sscanf(s, "%d", &i); repetition_claim = i != 0; } } else if (strstr(buf, "draw_count") == buf) { char *s = strchr(buf, '='); if (s) { int i = 0; s++; sscanf(s, "%d", &i); draw_count = i; } } else if (strstr(buf, "resign_count") == buf) { char *s = strchr(buf, '='); if (s) { int i = 0; s++; sscanf(s, "%d", &i); resign_count = i; } } else if (strstr(buf, "draw_threshold") == buf) { char *s = strchr(buf, '='); if (s) { int i = 0; s++; sscanf(s, "%d", &i); draw_threshold = abs(i); } } else if (strstr(buf, "resign_threshold") == buf) { char *s = strchr(buf, '='); if (s) { int i = LEGALWIN; s++; sscanf(s, "%d", &i); resign_threshold = -abs(i); } } } } static void write_config_file(void) { FILE *cf = fopen(configfile, "w"); if (!cf) return; if (user_alias && strlen(user_alias)) fprintf(cf, "user_alias = %s\n", user_alias); if (send_piece_descriptions == false) fprintf(cf, "send_piece_descriptions = %d\n", send_piece_descriptions); if (option_ms != MATE_SEARCH_ENABLE_DROP) fprintf(cf, "option_mate_search = %d\n", option_ms); if (user_variants_first == false) fprintf(cf, "user_variants_first = %d\n", user_variants_first); if (mask_dark_squares == true) fprintf(cf, "mask_dark_squares = %d\n", mask_dark_squares); if (fairy_file && strlen(fairy_file)) fprintf(cf, "fairy_file = %s\n", fairy_file); if (report_fail_low == true) fprintf(cf, "report_fail_low = %d\n", report_fail_low); if (report_fail_high == true) fprintf(cf, "report_fail_high = %d\n", report_fail_high); if (repetition_claim == false) fprintf(cf, "repetition_claim = %d\n", repetition_claim); fprintf(cf, "draw_count = %d\n", draw_count); fprintf(cf, "draw_threshold = %d\n", draw_threshold); fprintf(cf, "resign_count = %d\n", resign_count); fprintf(cf, "resign_threshold = %d\n", resign_threshold); fclose(cf); } #ifdef HAVE_READLINE /* Generator function for command completion. STATE lets us know whether * to start from scratch; without any state (i.e. STATE == 0), then we * start at the top of the list. */ char *command_generator (const char *text, int state) { static int list_index, len; const char *name = NULL; /* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and initializing the index variable to 0. */ if (!state) { list_index = 0; len = strlen (text); } /* Return the next name which partially matches from the command list. */ while ((name = help_topic[list_index].topic)) { list_index++; if (strncmp (name, text, len) == 0) return strdup(name); } /* If no names matched, then return NULL. */ return (char *)NULL; } /* Generator function for command completion. STATE lets us know whether * to start from scratch; without any state (i.e. STATE == 0), then we * start at the top of the list. */ char *variant_generator (const char *text, int state) { static int list_index, len; const char *name = NULL; /* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and initializing the index variable to 0. */ if (!state) { list_index = 0; len = strlen (text); } /* Return the next name which partially matches from the command list. */ while (list_index < num_standard_variants && (name = standard_variants[list_index].name)) { list_index++; if (strncmp (name, text, len) == 0) return strdup(name); } if (list_index >= num_standard_variants) { int n_alias = sizeof aliases / sizeof *aliases; int index = list_index - num_standard_variants; while (index < n_alias && (name = aliases[index].alias)) { list_index++; index++; if (strncmp (name, text, len) == 0) return strdup(name); } if (index >= n_alias) { index -= n_alias; while (index= argc) { fprintf(stderr, "error: no book specified\n"); exit(0); } n++; pgbook_file = strdup(argv[n]); printf("Using opening book %s\n", pgbook_file); //pgbook_file = strdup("bigbook.bin"); } else if (strstr(argv[n], "-log") || strstr(argv[n], "-newlog")) { const char *logfile = "sjaak.log"; if (n+1 < argc && argv[n+1][0] != '-') { logfile = argv[n+1]; n++; } const char *mode = "a"; if (strstr(argv[n], "-newlog")) mode = "w"; if (!f) f = fopen(logfile, mode); } else if (strstr(argv[n], "-xboard")) { xboard_mode = true; uci_mode = false; } else if (strstr(argv[n], "-uci")) { xboard_mode = false; uci_mode = true; uci_dialect = 'c'; free((void *)variant_name); variant_name = strdup("normal"); } else if (strstr(argv[n], "-usi")) { xboard_mode = false; uci_mode = true; uci_dialect = 's'; free((void *)variant_name); variant_name = strdup("shogi"); } else if (strstr(argv[n], "-ucci")) { xboard_mode = false; uci_mode = true; uci_dialect = 'C'; free((void *)variant_name); variant_name = strdup("xiangqi"); } else if (strstr(argv[n], "-no_user_variants")) { load_variant_file = false; } else if (strstr(argv[n], "-variant")) { if (n+1 < argc) { variant_name = strdup(argv[n+1]); n++; } } else if (strstr(argv[n], "-") == argv[n]) { fprintf(stderr, "Unknown option: %s\n", argv[n]); exit(0); } else { scan_variant_file(argv[n]); } } #ifdef DATADIR if (load_variant_file) scan_variant_file(DATADIR"/variants.txt"); #endif buf = (char *)malloc(65536); printf("%s version %s\n", PROGNAME, VERSIONSTR " " ARCHSTR); printf("Type 'help' for a list of commands and help topics\n"); initialise_hash_keys(); #ifdef SMP int ncore = get_number_of_cores(); printf("Machine has %d core%s\n", ncore, (ncore > 1)? "s" : ""); atexit(kill_threads); printf("Locks are implemented as %s\n", LOCK_DESCRIPTION); #endif #ifdef HAVE_READLINE if (stdin_is_terminal()) { rl_initialize(); //rl_read_init_file(readline_path); using_history(); stifle_history(256); //read_history(history_path); //atexit(write_history_file_on_exit); rl_attempted_completion_function = complete_sjaakii_command; } #endif /* Turn off buffering for stdout and stdin */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdin, NULL, _IONBF, 0); /* Write log output (for debugging purposes) */ //if (!f) f = fopen("xb.log", "a"); if (xboard_mode) { free((void *)variant_name); variant_name = NULL; } snprintf(fairy_alias, sizeof fairy_alias, "normal"); if (!variant_name) variant_name = strdup("normal"); /* Read persistent settings */ FILE *cf = fopen(configfile, "r"); if (cf) { if (f) fprintf(f, "Reading config file '%s'\n", configfile); read_config_file(cf); fclose(cf); } else { if (f) fprintf(f, "Cannot read config file '%s'\n", configfile); } atexit(write_config_file); /* Load variant description file */ if (fairy_file) scan_variant_file(fairy_file); game = create_variant_game(variant_name); if (game == NULL) { printf("Failed to start variant '%s', defaulting to 'normal'\n", variant_name); free((void *)variant_name); variant_name = strdup("normal"); game = create_variant_game(variant_name); } game->start_new_game(); game->set_default_output_function(log_xboard_output); game->set_xboard_output_function(NULL); game->set_uci_output_function(NULL); if (xboard_mode) { uci_mode = false; prompt = false; show_board = false; san = false; trapint = false; if (game && xboard_mode) rank_offset = (game->ranks != 10); relabel_chess_square_names(); game->set_xboard_output_function(log_xboard_output); game->set_uci_output_function(NULL); game->set_default_output_function(NULL); log_xboard_output("\n"); } if (uci_mode) { prompt = false; show_board = false; san = false; trapint = false; in_play = false; rank_offset = 1; uci_timeunit = 1; if (uci_dialect == 'C') uci_timeunit = 1000; if (game) delete game; game = create_variant_game(variant_name); game->set_transposition_table_size(hash_size); game->start_new_game(); if (uci_dialect == 's') relabel_shogi_square_names(); game->set_xboard_output_function(NULL); game->set_default_output_function(NULL); game->set_uci_output_function(log_xboard_output); } while (true) { input[0] = '\0'; prompt_str[0] = '\0'; if (show_board && game) game->print_board(); if (prompt) { int n = 0; n += snprintf(prompt_str+n, (sizeof prompt_str) - n, "#"); if (game) { n += snprintf(prompt_str+n, (sizeof prompt_str) - n, "[%s] ", game->get_name()); n += snprintf(prompt_str+n, (sizeof prompt_str) - n, "%d", (int)game->get_moves_played()); n += snprintf(prompt_str+n, (sizeof prompt_str) - n, "%s", (game->get_side_to_move() == WHITE)?"w":"b"); if (!in_play) n += snprintf(prompt_str+n, (sizeof prompt_str) - n, " (f)"); if (game->player_in_check(game->get_side_to_move())) n += snprintf(prompt_str+n, (sizeof prompt_str) - n, "+"); } else { n += snprintf(prompt_str+n, (sizeof prompt_str) - n, "[-]"); } n += snprintf(prompt_str+n, (sizeof prompt_str) - n, ">"); #ifdef HAVE_READLINE if (!stdin_is_terminal()) #endif printf("%s", prompt_str); } //if (!(may_ponder && game && game->ponder_move)|| keyboard_input_waiting()) { if (deferred[0]) { snprintf(input, sizeof input, "%s", deferred); deferred[0] = 0; } else if (keyboard_input_waiting() || (!may_ponder && !(game && game->analysing))) { #ifdef HAVE_READLINE if (stdin_is_terminal()) { char *readline_input = readline(prompt_str); if (readline_input && strlen(readline_input)) add_history(readline_input); snprintf(input, sizeof input, "%s", readline_input); free(readline_input); } else #endif if (!fgets(input, sizeof input, stdin)) break; } chomp(input); trim(input); #ifdef HAVE_READLINE if (!stdin_is_terminal()) { char *s = strchr(input, '#'); if (s) *s = '\0'; } #endif if (f) { fprintf(f, "< %s\n", input); fflush(f); } if (streq(input, "xboard") || streq(input, "xboard on")) { uci_mode = false; xboard_mode = true; prompt = false; show_board = false; san = false; trapint = false; if (game && xboard_mode) rank_offset = (game->ranks != 10); relabel_chess_square_names(); game->set_xboard_output_function(log_xboard_output); game->set_uci_output_function(NULL); game->set_default_output_function(NULL); log_xboard_output("\n"); } else if (streq(input, "xboard off")) { xboard_mode = false; prompt = true; show_board = true; san = true; trapint = true; rank_offset = 1; relabel_chess_square_names(); log_xboard_output("\n"); game->set_xboard_output_function(NULL); game->set_default_output_function(log_xboard_output); } else if (streq(input, "uci") || streq(input, "uci on") || streq(input, "ucci") || streq(input, "ucci on") || streq(input, "usi") || streq(input, "usi on")) { uci_mode = true; uci_dialect = input[1]; prompt = false; show_board = false; san = false; trapint = false; in_play = false; rank_offset = 1; if (input[2] == 'c') uci_dialect = 'C'; uci_timeunit = 1; if (uci_dialect == 'C') uci_timeunit = 1000; free((void *)variant_name); switch (uci_dialect) { case 's': variant_name = strdup("shogi"); break; case 'C': variant_name = strdup("xiangqi"); break; default: variant_name = strdup("normal"); } if (game) delete game; game = create_variant_game(variant_name); game->set_transposition_table_size(hash_size); game->start_new_game(); if (input[1] == 's') relabel_shogi_square_names(); game->set_xboard_output_function(NULL); game->set_default_output_function(NULL); game->set_uci_output_function(log_xboard_output); log_xboard_output("\n"); log_xboard_output("id name %s %s %s\n", PROGNAME, VERSIONSTR, ARCHSTR); log_xboard_output("id author Evert Glebbeek\n"); //log_xboard_output("option name OwnBook type check default true\n"); /* Hash size: 1MB - 1 GB */ const char *option_name = " name"; if (uci_dialect == 'C') option_name = ""; log_xboard_output("option%s Hash type spin default 48 min 1 max 4096\n", option_name); #ifdef SMP log_xboard_output("option%s Cores type spin default 1 min 1 max %d\n", option_name, MAX_THREADS); #endif log_xboard_output("option%s Ponder type check default true\n", option_name); log_xboard_output("option name UCI_Chess960 type check default true\n"); log_xboard_output("option%s UCI_Variant type combo default %s", option_name, variant_name); log_xboard_output(" var %s var chess960", standard_variants[0].name); for (int n = 1; nset_default_output_function(log_xboard_output); game->set_uci_output_function(NULL); relabel_chess_square_names(); } else if (streq(input, "isready") && uci_mode) { log_xboard_output("readyok\n"); } else if ((strstr(input, "setoption usemillisec") == input) && uci_mode) { uci_timeunit = 1000; if (strstr(input, "true")) uci_timeunit = 1; } else if ((strstr(input, "setoption name Hash") == input || strstr(input, "setoption Hash") == input) && uci_mode) { /* TODO: set the size of the hash table */ unsigned long long memory_size = hash_size * sizeof(hash_table_entry_t); char *s = strstr(input, "value"); if (s) { sscanf(s+6, "%llu", &memory_size); /* Convert to bytes */ memory_size <<= 20; /* Reserve default */ if (memory_size > 10<<20) memory_size -= 5<<20; } else { sscanf(input+13, "%llu", &memory_size); /* Convert to bytes */ memory_size <<= 20; /* Reserve default */ if (memory_size > 10<<20) memory_size -= 5<<20; } hash_size = size_t(memory_size / sizeof(hash_table_entry_t)); } else if ((strstr(input, "setoption name UCI_Variant") == input || strstr(input, "setoption UCI_Variant") == input) && uci_mode) { char *s = strstr(input, "value"); if (s) { s += 6; while (*s && isspace(*s)) s++; if (s[0]) { /* Trim trailing spaces */ char *p = s + strlen(s)-1; while (*p == ' ') {*p = 0; p--; } free((void *)variant_name); variant_name = strdup(s); if (game) delete game; game = create_variant_game(variant_name); game->set_transposition_table_size(hash_size); game->start_new_game(); if (uci_dialect == 's') relabel_shogi_square_names(); uci_kxr = false; if (streq(variant_name, "chess960")) uci_kxr = true; } } else { /* TODO: select variants in ucci mode */ } } else if (strstr(input, "setoption name UCI_Chess960") == input && uci_mode) { char *s = strstr(input, "value"); if (s) { s += 6; uci_kxr = false; if (strstr(s, "true") == s) uci_kxr = true; } } else if (strstr(input, "setoption name Ponder") == input && uci_mode) { #ifdef SMP } else if (strstr(input, "setoption name Cores") == input && uci_mode) { int threads = 0; char *s = strstr(input, "value"); if (s) { s += 6; sscanf(s, "%d", &threads); kill_threads(); if (threads > 0) init_threads(threads); if (show_board) printf("Started %d threads\n", get_number_of_threads()); } #endif } else if ((streq(input, "ucinewgame") || streq(input, "uccinewgame") || streq(input, "usinewgame")) && uci_mode) { if (game) delete game; game = create_variant_game(variant_name); game->set_transposition_table_size(hash_size); game->start_new_game(); if (uci_dialect == 's') relabel_shogi_square_names(); num_games++; if (f) fprintf(f, "# game %d\n", num_games); } else if (strstr(input, "banmoves") && uci_mode) { } else if (strstr(input, "position") && uci_mode) { char *p = strstr(input, " "); while (p && *p && p[0]==' ') p++; assert(game); if (strstr(p, "startpos") == p) { /* Game from start position */ /* We need to return to the first node in the game struct and * then replay all the moves from the beginning to the current * position. */ p = strstr(p, "moves"); if (p && *p) p+=6; replay_game(game, p); } else if (strstr(p, "fen") == p) { /* Game from FEN string */ p+=4; game->setup_fen_position(p); p = strstr(p, "moves"); if (p && *p) p+=6; replay_game(game, p); } else if (strstr(p, "sfen") == p) { /* Game from sFEN string */ /* Translate SFEN to FEN */ char fen[256] = { 0 }; int n = 0; p += 5; /* Skip space */ while (*p && isspace(*p)) p++; /* Copy position verbatim */ while (*p && !isspace(*p)) { fen[n++] = *p; p++; } while (*p && isspace(*p)) p++; char side = *p; while (*p && !isspace(*p)) p++; while (*p && isspace(*p)) p++; /* Flip white and black in side to move */ side = (side == 'w') ? 'b' : 'w'; /* Copy pieces in holdings */ n += snprintf(fen+n, (sizeof fen) - n, " ["); if (*p != '-') { while (*p && !isspace(*p)) { int c = 1; if (isdigit(*p)) { sscanf(p, "%d", &c); p++; } while (c>0) { fen[n++] = *p; c--; } p++; } } n += snprintf(fen+n, (sizeof fen) - n, "] %c", side); int ply = 1; sscanf(p, "%d", &ply); n += snprintf(fen+n, (sizeof fen) - n, " 0 %d", (ply+1)/2); game->setup_fen_position(fen); p = strstr(p, "moves"); if (p && *p) p+=6; replay_game(game, p); } } else if (streq(input, "stop") && uci_mode) { } else if (strstr(input, "go") == input && uci_mode) { const char *p = ""; int depth = MAX_SEARCH_DEPTH; char *s; /* Set defaults */ set_time_per_move(&game->clock, 5000); game->clock.movestogo = 0; game->clock.time_inc = 0; /* parse options */ if ((s = strstr(input, "movetime"))) { sscanf(s+9, "%d", &time_per_move); set_time_per_move(&game->clock, time_per_move * uci_timeunit); } if ((s = strstr(input, " movestogo"))) { sscanf(s+10, "%d", &game->clock.movestogo); } if ((s = strstr(input, "infinite"))) { set_infinite_time(&game->clock); } if ((s = strstr(input, " time"))) { int time_left; sscanf(s+5, "%d", &time_left); game->clock.time_left = time_left * uci_timeunit; set_time_for_game(&game->clock); } if ((s = strstr(input, "wtime"))) { int time_left; sscanf(s+6, "%d", &time_left); if (my_colour == WHITE || (uci_dialect == 's' && my_colour == BLACK)) { game->clock.time_left = time_left * uci_timeunit; set_time_for_game(&game->clock); } } if ((s = strstr(input, "btime"))) { int time_left; sscanf(s+6, "%d", &time_left); if (my_colour == BLACK || (uci_dialect == 's' && my_colour == WHITE)) { game->clock.time_left = time_left * uci_timeunit; set_time_for_game(&game->clock); } } if ((s = strstr(input, " increment"))) { int inc; sscanf(s+5, "%d", &inc); game->clock.time_inc = inc * uci_timeunit; } if ((s = strstr(input, "winc"))) { int inc; sscanf(s+5, "%d", &inc); if (my_colour == WHITE || (uci_dialect == 's' && my_colour == BLACK)) { game->clock.time_inc = inc * uci_timeunit; } } if ((s = strstr(input, "binc"))) { int inc; sscanf(s+5, "%d", &inc); if (my_colour == BLACK || (uci_dialect == 's' && my_colour == WHITE)) { game->clock.time_inc = inc * uci_timeunit; } } if ((s = strstr(input, "mate"))) { /* Just do a normal N-ply search instead */ sscanf(s+5, "%d", &depth); set_infinite_time(&game->clock); } if ((s = strstr(input, "depth"))) { sscanf(s+6, "%d", &depth); set_infinite_time(&game->clock); } if ((s = strstr(input, "byoyomi"))) { /* Traditional Shogi time-control (USI) */ int bt = 0; sscanf(s+7, "%d", &bt); bt *= uci_timeunit; if (bt > game->clock.time_left) { game->clock.time_inc = bt; set_time_for_game(&game->clock); } else { set_time_per_move(&game->clock, bt); game->clock.movestogo = 1; } } uci_clock_handler = game->clock.check_clock; game->check_keyboard = NULL; game->pondering = false; game->ponder_move = 0; if ((s = strstr(input, "ponder"))) { game->check_keyboard = uci_keyboard_input_on_ponder; game->ponder_move = game->move_list[game->moves_played-1]; game->pondering = true; game->clock.check_clock = NULL; } if (game->think(depth) == SEARCH_OK) { move_t move = game->get_last_move(); log_xboard_output("bestmove %s", move_to_lan_string(move, false, uci_kxr)); if (game->ponder_move) log_xboard_output(" ponder %s", move_to_lan_string(game->ponder_move, false, uci_kxr)); log_xboard_output("\n"); } game->clock.check_clock = uci_clock_handler; game->pondering = false; } else if (strstr(input, "ponderhit") && uci_mode) { /* Nothing special yet... */ } else if (strstr(input, "help")) { print_help(input+4); } else if (strstr(input, "#") == input) { } else if (strstr(input, "echo ") == input) { log_xboard_output("%s", input+5); } else if (strstr(input, "protover")) { send_variants_to_xboard(); send_fairy_menu_to_xboard(); log_xboard_output("feature option=\"Mate search -combo %sDisabled /// %sEnabled for drop games /// %sEnabled\"\n", (option_ms == MATE_SEARCH_DISABLED) ? "*" : "", (option_ms == MATE_SEARCH_ENABLE_DROP) ? "*" : "", (option_ms == MATE_SEARCH_ENABLED) ? "*" : ""); log_xboard_output("feature option=\"Draw offer threshold -spin %d 0 1000\"\n", draw_threshold); log_xboard_output("feature option=\"Moves before draw offer (0 to disable) -spin %d 0 1000\"\n", draw_count); log_xboard_output("feature option=\"Resign threshold -spin %d 100 %d\"\n", abs(resign_threshold), LEGALWIN); log_xboard_output("feature option=\"Moves before resigning (0 to disable) -spin %d 0 1000\"\n", resign_count); log_xboard_output("feature option=\"Send 'piece' descriptions -check %d\"\n", send_piece_descriptions); log_xboard_output("feature option=\"Mark holes in board -check %d\"\n", !mask_dark_squares); log_xboard_output("feature option=\"List user-defined variants before buildin variants -check %d\"\n", user_variants_first); log_xboard_output("feature option=\"Report fail low -check %d\"\n", report_fail_low); log_xboard_output("feature option=\"Report fail high -check %d\"\n", report_fail_high); log_xboard_output("feature option=\"Claim repetitions -check %d\"\n", repetition_claim); log_xboard_output("feature option=\"Set variant alias -string %s\"\n", user_alias?user_alias:""); log_xboard_output("feature option=\"Variant configuration file -file %s\"\n", fairy_file?fairy_file:""); log_xboard_output("feature done=1\n"); } else if (strstr(input, "accepted") == input) { } else if (strstr(input, "rejected") == input) { } else if (streq(input, "variant") || streq(input, "variants")) { printf("Known variants:\n"); size_t max_len = 0; for (int n = 0; n max_len) max_len = l; } for (int n = 0; n max_len) max_len = l; } for (int n = 0; n0; c--) printf(" "); printf("(%dx%d", standard_variants[n].files, standard_variants[n].ranks); if (standard_variants[n].holdings) printf("+%d", standard_variants[n].holdings); printf(")\n"); } for (int n = 0; n0; c--) printf(" "); printf("(%dx%d", custom_variants[n].files, custom_variants[n].ranks); printf(")\t[%s]\n", custom_variants[n].filename); } } else if (strstr(input, "load") == input) { char *s = input+5; char *p; while (isspace(*s)) s++; p = s + strlen(s)-1; while (p > s && isspace(*p)) { *p = '\0'; p--; } invalidate_variant_file(s); scan_variant_file(s); for (int n = 0; n s && isspace(*p)) { *p = '\0'; p--; } invalidate_variant_file(s); } else if (strstr(input, "variant ") == input || streq(input, "new")) { bool override_fairy = false; if (strstr(input, "variant")) { char *s = input + 7; while (*s && isspace(*s)) s++; if (s[0]) { /* Trim trailing spaces */ char *p = s + strlen(s)-1; while (*p == ' ') {*p = 0; p--; } free((void *)variant_name); variant_name = NULL; if (user_alias && strstr(user_alias, s) == user_alias) { char *p = strstr(user_alias, "="); if (p) { p++; variant_name = trim(strdup(p)); override_fairy = true; } } if (!variant_name) variant_name = strdup(s); /* Remove size-override for variant fairy */ s = strstr((char *)variant_name, "fairy"); if (s && s != variant_name && s[-1] == '_') { snprintf((char *)variant_name, strlen(variant_name), "fairy"); } } } else { /* "new" should switch to variant "normal" in XBoard mode. */ if (xboard_mode) { free((void *)variant_name); variant_name = strdup("normal"); } } if (game) delete game; game = create_variant_game(variant_name); if (!game) { log_xboard_output("Error (cannot start variant game): '%s'\n", variant_name); } else { //game->book = open_opening_book(pgbook_file); game->set_transposition_table_size(hash_size); game->start_new_game(); if (xboard_mode && (game->xb_setup || streq(variant_name, "fairy") || override_fairy)) { const char *fen = game->start_fen; if (mask_dark_squares) fen = filter_dark_squares_fen(game->start_fen); if ((game->xb_setup == NULL || game->xb_setup[0] == 0) && (streq(variant_name, "fairy") || override_fairy)) { const char *parent = find_real_variant_name(variant_name); if (streq(parent, "chess")) parent = "normal"; log_xboard_output("setup () %dx%d+%d_%s %s\n", game->files, game->ranks, game->holdsize, parent, fen); } else { if (game->xb_setup && game->xb_setup[strlen(game->xb_setup)-1] == ')') { const char *parent_name = "fairy"; if (game->xb_parent && game->xb_parent[0]) parent_name = game->xb_parent; log_xboard_output("setup %s %dx%d+%d_%s %s\n", game->xb_setup ? game->xb_setup : "()", game->files, game->ranks, game->holdsize, parent_name, fen); } else log_xboard_output("setup %s %s\n", game->xb_setup ? game->xb_setup : "()", fen); } if (send_piece_descriptions) game->write_piece_descriptions(true); } if (strstr(input, "new")) { my_colour = BLACK; depth = MAX_SEARCH_DEPTH; num_games++; in_play = true; if (f) fprintf(f, "# game %d\n", num_games); } } if (game && xboard_mode) rank_offset = (game->ranks != 10); relabel_chess_square_names(); } else if (strstr(input, "option") == input) { #if 0 if (strstr(input+7, "Opening book (polyglot)")) { char *s = strstr(input, "="); char *eol = input + strlen(input)-1; if (s) s++; /* Strip leading and trailing spaces */ while (*s && isspace(*s)) s++; while (isspace(*eol)) { *eol='\0'; eol--; } log_xboard_output("# %s\n", s); free(pgbook_file); pgbook_file = strdup(s); if (game) { close_opening_book(game->book); game->book = open_opening_book(pgbook_file); } } #endif #if 0 } else if (strstr(input, "book") == input) { char *s = input+4; char *eol = input + strlen(input)-1; if (s) s++; /* Strip leading and trailing spaces */ while (*s && isspace(*s)) s++; while (isspace(*eol)) { *eol='\0'; eol--; } if (streq(s, "off")) { free(pgbook_file); pgbook_file = NULL; if (game) { close_opening_book(game->book); game->book = NULL; } } else { free(pgbook_file); pgbook_file = strdup(s); if (game) { close_opening_book(game->book); game->book = open_opening_book(pgbook_file); } } #endif if (strstr(input+7, "Draw offer threshold")) { char *s = strstr(input, "-"); if (s) { int i = draw_threshold; sscanf(s+1, "%d", &i); draw_threshold = i; } } if (strstr(input+7, "Moves before draw offer (0 to disable)")) { char *s = strstr(input, "-"); if (s) { int i = draw_count; sscanf(s+1, "%d", &i); draw_count = i; } } if (strstr(input+7, "Resign threshold")) { char *s = strstr(input, "-"); if (s) { int i = resign_threshold; sscanf(s+1, "%d", &i); resign_threshold = -abs(i); } } if (strstr(input+7, "Moves before resigning (0 to disable)")) { char *s = strstr(input, "-"); if (s) { int i = resign_count; sscanf(s+1, "%d", &i); resign_count = i; } } if (strstr(input+7, "Mate search")) { char *s = strstr(input, "="); if (s) { s++; if (strstr(s, "Disabled") == s) { option_ms = MATE_SEARCH_DISABLED; } else if (strstr(s, "Enabled for drop games") == s) { option_ms = MATE_SEARCH_ENABLE_DROP; } else if (strstr(s, "Enabled") == s) { option_ms = MATE_SEARCH_ENABLED; } } } if (strstr(input+7, "Variant fairy selects")) { char *s = strstr(input, "="); if (s) { snprintf(fairy_alias, sizeof fairy_alias, "%s", s+1); s = strstr(fairy_alias, " "); if (s) *s = 0; } } if (strstr(input+7, "Send 'piece' descriptions")) { char *s = strstr(input, "="); if (s) { s++; int i = send_piece_descriptions; sscanf(s, "%d", &i); send_piece_descriptions = i != 0; } } if (strstr(input+7, "List user-defined variants before buildin variants")) { char *s = strstr(input, "="); if (s) { s++; int i = user_variants_first; sscanf(s, "%d", &i); user_variants_first = (i != 0); send_variants_to_xboard(); } } if (strstr(input+7, "Mark holes in board")) { char *s = strstr(input, "="); if (s) { s++; int i = !mask_dark_squares; sscanf(s, "%d", &i); mask_dark_squares = !(i != 0); } } if (strstr(input+7, "Claim repetitions")) { char *s = strstr(input, "="); if (s) { s++; int i = repetition_claim; sscanf(s, "%d", &i); repetition_claim = i != 0; } } if (strstr(input+7, "Report fail high")) { char *s = strstr(input, "="); if (s) { s++; int i = report_fail_high; sscanf(s, "%d", &i); report_fail_high = i != 0; } } if (strstr(input+7, "Report fail low")) { char *s = strstr(input, "="); if (s) { s++; int i = report_fail_low; sscanf(s, "%d", &i); report_fail_low = i != 0; } } if (strstr(input+7, "Set variant alias")) { char *s = strstr(input, "="); if (s) { s++; free(user_alias); user_alias = trim(strdup(s)); log_xboard_output("feature done=0\n"); send_variants_to_xboard(); log_xboard_output("feature done=1\n"); } } if (strstr(input+7, "Variant configuration file")) { char *s = input + 34; char *eol = input + strlen(input)-1; /* Strip leading and trailing spaces */ while (*s && isspace(*s)) s++; while (isspace(*eol)) { *eol='\0'; eol--; } invalidate_variant_file(fairy_file); free(fairy_file); fairy_file = strdup(s); scan_variant_file(fairy_file); /* Try to work around a problem with XBoard rejecting the "reset" option by sending our * configuration anyway. This seems to be the best we can do in this situation. */ log_xboard_output("feature done=0\n"); send_variants_to_xboard(); send_fairy_menu_to_xboard(); log_xboard_output("feature done=1\n"); } write_config_file(); } else if (strstr(input, "memory") == input) { unsigned long int memory_size; sscanf(input+7, "%lu", &memory_size); /* Convert to bytes */ memory_size <<= 20; size_t nelem = memory_size / sizeof(hash_table_entry_t); /* Round to the next-lowest power of 2 */ nelem |= (nelem >> 1); nelem |= (nelem >> 2); nelem |= (nelem >> 4); nelem |= (nelem >> 8); nelem |= (nelem >> 16); nelem |= (nelem >> 32*(sizeof(size_t)>4)); nelem >>= 1; nelem++; hash_size = nelem; game->set_transposition_table_size(hash_size); } else if (strstr(input, "analyze") || strstr(input, "analyse")) { if (game) { in_play = false; //game->set_xboard_output_function(log_xboard_output); game->analysing = true; } } else if (strstr(input, "force setboard")) { char *p = strstr(input+7, " "); while (p && *p && p[0]==' ') p++; if (game) game->setup_fen_position(p); in_play = false; } else if (strstr(input, "force") == input) { game->draw_count = 0; game->resign_count = 0; in_play = false; } else if (strstr(input, "undo") == input) { if (game->draw_count) game->draw_count--; if (game->resign_count) game->resign_count--; game->takeback(); game->clock.time_left = game->move_clock[game->moves_played]; } else if (strstr(input, "rules") == input) { if (game) game->print_rules(); } else if (strstr(input, "wikirules") == input) { if (game) game->print_wiki_rules(); } else if (strstr(input, "pieceinfo") == input) { game->print_pieces(); } else if (strstr(input, "remove") || strstr(input, "takeback")) { if (game->draw_count) game->draw_count--; if (game->resign_count) game->resign_count--; game->takeback(); game->clock.time_left = game->move_clock[game->moves_played]; game->takeback(); game->clock.time_left = game->move_clock[game->moves_played]; } else if (strstr(input, "setboard") == input) { char *p = strstr(input, " "); while (p && *p && p[0]==' ') p++; if (game) game->setup_fen_position(p); if (!xboard_mode) in_play = false; } else if (strstr(input, "perft") == input) { if (game) { int depth = 6; int root = 0; char *s = input + 5; while (*s && isspace(*s)) s++; if (*s) { sscanf(s, "%d", &depth); while(*s && isdigit(*s)) s++; } while (*s && isspace(*s)) s++; if (*s) { sscanf(s, "%d", &root); } #ifdef __unix__ if (trapint) old_signal_handler = signal(SIGINT, interrupt_computer); #endif abort_search = false; uint64_t t = get_timer(); for (int n = 1; nstart_new_game(); game->setup_fen_position("8/k7/3p4/p2P1p2/P2P1P2/8/8/K7 w - - bm Kb1"); play_state_t status = game->think(depth); delete game; } else if (strstr(input, "test wac") == input) { run_test_suite(1000, wac_test); } else if (strstr(input, "test sts") == input) { run_test_suite(1000, sts_test); } else if (strstr(input, "test static_qs") == input) { printf("%d\n", game->static_qsearch(LEGALWIN)); } else if (strstr(input, "test see") == input) { move_t move = game->move_string_to_move(input+8); printf("%d\n", game->see(move)); } else if (strstr(input, "test smp") == input) { #ifdef SMP int cores = ncore/2; int depth = 12; char *s = input + 8; while (*s && isspace(*s)) s++; if (*s == '-') { if (*s) sscanf(s, "- %d", &depth); } else { if (*s) sscanf(s, "%d %d", &cores, &depth); } test_smp(cores, depth); #endif } else if (strstr(input, "test chase") == input) { chase_state_t state = game->test_chase(); switch (state) { case NO_CHASE: printf("No chase\n"); break; case DRAW_CHASE: printf("Legal chase (draw)\n"); break; case LOSE_CHASE: printf("Illegal chase (lose)\n"); break; case WIN_CHASE: printf("Illegal chase (win)\n"); break; } } else if (strstr(input, "test") == input) { printf("Unknown test: %s\n", input+4); } else if (strstr(input, "sd inf")) { depth = MAX_SEARCH_DEPTH; } else if (strstr(input, "sd")) { sscanf(input, "sd %d", &depth); } else if (strstr(input, "threads") || strstr(input, "cores")) { #ifdef SMP int threads = 0; char *s = input; while (*s && isalpha(*s)) s++; sscanf(s, "%d", &threads); kill_threads(); if (threads > 0) init_threads(threads); if (show_board) printf("Started %d threads\n", get_number_of_threads()); #endif } else if (strstr(input, "go")) { if (game) { my_colour = game->get_side_to_move(); in_play = true; /* Correctly set the number of moves to go */ if (game->clock.movestotc) { size_t moves_played = game->get_moves_played() / 2; if (my_colour == WHITE) moves_played += (game->get_moves_played() % 2); moves_played %= game->clock.movestotc; game->clock.movestogo = game->clock.movestotc - (int)moves_played; } } } else if (strstr(input, "st inf")) { if (game) set_infinite_time(&game->clock); } else if (strstr(input, "st ")) { float tpm = 5; sscanf(input+3, "%g", &tpm); time_per_move = int(tpm * 1000); set_time_per_move(&game->clock, time_per_move); if (nps > 0) game->clock.max_nodes = nps * time_per_move; } else if (strstr(input, "computer") == input) { } else if (strstr(input, "name") == input) { } else if (strstr(input, "rating") == input) { } else if (strstr(input, "random")) { sgenrand((unsigned int)time(NULL)); game->random_ok = true; } else if (strstr(input, "easy") || streq(input, "ponder off")) { may_ponder = false; } else if (strstr(input, "hard") || streq(input, "ponder on")) { may_ponder = true; } else if (strstr(input, "nopost") == input || strstr(input, "post off") == input) { game->set_xboard_output_function(NULL); } else if (strstr(input, "post") == input) { game->set_xboard_output_function(log_xboard_output); } else if (strstr(input, "trace on")) { game->trace = true; } else if (strstr(input, "trace off")) { game->trace = false; } else if (strstr(input, "?") == input) { } else if (strstr(input, "hint") == input) { if (game && game->ponder_move) log_xboard_output("Hint: %s\n", move_to_lan_string(game->ponder_move)); } else if (strstr(input, "otim") == input) { } else if (strstr(input, "ping") == input) { log_xboard_output("pong %s\n", input+5); } else if (strstr(input, "draw") == input) { /* Process draw offer */ if (game && game->draw_count > draw_count) log_xboard_output("offer draw\n"); } else if (strstr(input, "result") == input) { } else if (strstr(input, "time") == input) { set_time_from_string(game, input+5); } else if (strstr(input, "nps")) { /* This is a convoluted mess... */ sscanf(input+4, "%d", &nps); /* If we have a fixed time per move, then we can set a maximum number of nodes. * Otherwise... things get complicated. */ game->clock.max_nodes = 0; if (time_per_move > 0 && nps > 0) game->clock.max_nodes = nps * time_per_move; } else if (strstr(input, "maxnodes")) { unsigned int nodes = 0; sscanf(input+9, "%u", &nodes); game->clock.max_nodes = nodes; } else if (strstr(input, "level") == input) { set_timecontrol_from_string(game, input+6); } else if (streq(input, "quit") || streq(input, "exit") || streq(input, "bye")) { if (game) delete game; free(buf); exit(0); } else if (streq(input, "eval")) { if (game) { //game->root_board = game->board; printf("Static evaluation: %d\n", game->eval()); } } else if (strstr(input, "prompt on") == input) { prompt = true; } else if (strstr(input, "prompt off") == input) { printf("\n"); prompt = false; } else if (strstr(input, "board on") == input) { show_board = true; } else if (strstr(input, "board off") == input) { show_board = false; } else if (strstr(input, "san on") == input) { san = true; } else if (strstr(input, "san off") == input) { san = false; } else if (streq(input, "bitboards")) { if (game) game->print_bitboards(); } else if (streq(input, "board")) { if (game) game->print_board(); } else if (streq(input, "settings")) { printf("Xboard mode : %s\n", xboard_mode ? "on" : "off"); printf("UCI mode : %s\n", uci_mode ? "on" : "off"); printf("UCI dialect : %c\n", uci_dialect); printf("UCI timeunit : %dms\n", uci_timeunit); printf("\n"); printf("Prompt : %s\n", prompt ? "on" : "off"); printf("Board : %s\n", show_board ? "on" : "off"); printf("SAN notation : %s\n", san ? "on" : "off"); printf("Trap SIGINT : %s\n", trapint ? "on" : "off"); printf("\n"); printf("Time control : %d moves in %ds + %dms\n", tc_moves, tc_time, tc_inc); printf("Time per move : %ds\n", time_per_move); printf("Max depth : %d\n", depth); printf("Max nodes : %llu\n", (unsigned long long) (game ? game->clock.max_nodes : 0)); } else if (streq(input, "pieces")) { if (game) game->write_piece_descriptions(); } else if (strstr(input, "show attackers ") == input) { const char *s = input + 15; while (*s && isspace(*s)) s++; int file, rank; int n = 0; file = *s - 'a'; s++; sscanf(s, "%d %n", &rank, &n); s += n; rank -= rank_offset; /* Xboard counts ranks from 0 for large boards */ int square = game->pack_rank_file(rank, file); game->print_attacker_bitboard(square); } else if (strstr(input, "show attacks ") == input) { const char *s = input + 13; while (*s && isspace(*s)) s++; int file, rank; int n = 0; file = *s - 'a'; s++; sscanf(s, "%d %n", &rank, &n); s += n; rank -= rank_offset; /* Xboard counts ranks from 0 for large boards */ int square = game->pack_rank_file(rank, file); game->print_attack_bitboard(square); } else if (streq(input, "fen")) { if (game) printf("%s\n", game->make_fen_string()); } else if (streq(input, "moves")) { if (game) { movelist_t movelist; game->generate_legal_moves(&movelist); int k; printf("%d moves\n", movelist.num_moves); for (k=0; kgenerate_legal_moves(&movelist); int k; printf("%d moves\n", movelist.num_moves); for (k=0; kgenerate_moves(&movelist); int k; printf("%d moves\n", movelist.num_moves); for (k=0; kranks*game->files; square++) { if (streq(input+5, square_names[square])) { send_legal_move_targets(game, square); break; } } } else if (strstr(input, "put")) { /* No action required */ } else if (strstr(input, "hover")) { /* TODO */ } else if (strstr(input, "readfen") || strstr(input, "readepd")) { FILE *f = fopen(input+8, "r"); if (f) { char s[4096]; if (fgets(s, sizeof s, f)) { if (game) { game->setup_fen_position(s); game->print_board(); } } fclose(f); } else { printf("Can't open file: %s\n", input+8); } } else if (prompt && input[0] == '!') { if (system(input+1) == -1) printf("Cannot execute command %s\n", input+1); } else if (input[0]) { /* Can the input be interpreted as a move? Or is it an unknown * command? */ if (!input_move(game, input)) { log_xboard_output("Error (Illegal move or unknown command): %s\n", input); if (f) fprintf(f, "In position '%s'\n", game->make_fen_string()); } else { if (!uci_mode) report_game_status(game, game->get_game_end_state(), input); } } /* Should the computer play a move? */ if (game && in_play && !game->analysing && !uci_mode) { memset(deferred, 0, sizeof deferred); game->check_keyboard = keyboard_input_on_move; if (game->get_side_to_move() == my_colour) { /* Check whether NPS time control is sane. */ if (nps>-1 && !time_per_move) { log_xboard_output("telluser Warning: specifying NPS without fixed time per move is not implemented\n"); game->clock.max_nodes = nps; } game->clock.pondering = false; //log_engine_output("Searching position %s\n", make_fen_string(game, NULL)); movelist_t legal_moves; game->generate_legal_moves(&legal_moves); #ifdef __unix__ if (trapint) old_signal_handler = signal(SIGINT, interrupt_computer); #endif game->move_clock[game->moves_played] = game->clock.time_left; game->show_fail_low = report_fail_low; game->show_fail_high = report_fail_high; game->repetition_claim = repetition_claim; game->resign_threshold = resign_threshold; game->draw_threshold = draw_threshold; game->option_ms = option_ms; play_state_t status = game->think(depth); #ifdef __unix__ if (trapint) signal(SIGINT, old_signal_handler); #endif game->clock.time_left -= peek_timer(&game->clock); game->clock.time_left += tc_inc; game->move_clock[game->moves_played] = game->clock.time_left; if (!xboard_mode && game->clock.check_clock) { int time = std::max(0, game->clock.time_left); int min = time / 60000; float sec = float((time - min * 60000) / 1000.); log_xboard_output("Time remaining %d:%.2f\n", min, sec); } if (status == SEARCH_OK) { move_t move = game->get_last_move(); /* Offer draw of resign, as appropriate */ if (draw_count>0 && game->draw_count > draw_count) { game->draw_count /= 2; /* Wait a while before offering again */ log_xboard_output("offer draw\n"); } else if (resign_count>0 && game->resign_count > resign_count) log_xboard_output("resign\n"); if (san) { log_xboard_output("move %s\n", move_to_short_string(move, &legal_moves)); } else { char *s = strdup(move_to_lan_string(move)); char *p = strstr(s, ","); if (p) { /* Multi-leg moves should be sent in two goes. */ *p = 0; log_xboard_output("move %s,\n", s); log_xboard_output("move %s\n", p+1); } else { log_xboard_output("move %s\n", s); } free(s); } if (game->clock.movestogo) { game->clock.movestogo--; if (!game->clock.movestogo) { game->clock.movestogo = game->clock.movestotc; game->clock.time_left += tc_time; } } //report_game_status(game, status, input); report_game_status(game, game->get_game_end_state(), input); } else { in_play = false; } } else if (may_ponder && game->ponder_move) { /* Ponder */ bool (*old_keyboard_handler)(struct game_t *game) = game->check_keyboard; bool (*old_clock_handler)(const struct chess_clock_t *clock) = game->clock.check_clock; game->check_keyboard = interrupt_ponder; game->clock.check_clock = NULL; game->ponder(); game->check_keyboard = old_keyboard_handler; game->clock.check_clock = old_clock_handler; } } if (game && game->analysing) { bool (*old_keyboard_handler)(struct game_t *game) = game->check_keyboard; bool (*old_clock_handler)(const struct chess_clock_t *clock) = game->clock.check_clock; game->analyse_fen = NULL; game->analyse_new = false; game->analyse_undo = 0; game->analyse_moves_played = game->moves_played; game->check_keyboard = keyboard_input_analyse; game->clock.check_clock = NULL; game->analyse(); game->check_keyboard = old_keyboard_handler; game->clock.check_clock = old_clock_handler; if (game->analyse_new) game->start_new_game(); for (int n=0; nanalyse_undo; n++) game->takeback(); if (game->analyse_fen) { game->setup_fen_position(game->analyse_fen); free((void *)game->analyse_fen); game->analyse_fen = NULL; } } } if (prompt) printf("\n"); return 0; }