From ae338a820ef1c16d4399958613bbc0b908904b91 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Thu, 9 Jun 2011 10:17:55 +0200 Subject: [PATCH] version 1.4.63b --- COPYING | 680 ++++++------ ChangeLog | 467 ++++---- README1.3 | 868 ++++++++-------- README1.4w | 138 ++-- attack.c | 448 ++++---- attack.h | 74 +- board.c | 984 +++++++++--------- board.h | 140 ++-- book.c | 844 +++++++------- book.h | 64 +- book_make.c | 2167 ++++++++++++++++++------------------ book_make.h | 40 +- book_merge.c | 608 +++++----- book_merge.h | 36 +- colour.c | 110 +- colour.h | 66 +- config.h | 6 +- configure | 20 +- configure.ac | 2 +- engine.c | 225 ++-- engine.h | 72 +- epd.c | 894 ++++++++-------- epd.h | 40 +- fen.c | 784 +++++++------- fen.h | 48 +- game.c | 722 ++++++------ game.h | 146 ++-- gui.c | 4 - hash.c | 256 +++--- hash.h | 78 +- ini.c | 4 - io.c | 2 - io.h | 106 +- line.c | 408 ++++---- line.h | 64 +- list.c | 550 +++++----- list.h | 108 +- main.c | 1341 +++++++++++----------- main.h | 38 +- mainloop.c | 206 ++-- mainloop.h | 52 +- move.c | 752 +++++++------- move.h | 120 +- move_do.c | 726 ++++++------ move_do.h | 38 +- move_gen.c | 656 ++++++------ move_gen.h | 42 +- move_legal.c | 230 ++-- move_legal.h | 48 +- option.c | 795 +++++++------- option.h | 196 ++-- parse.c | 524 +++++----- parse.h | 88 +- pgn.c | 1282 +++++++++++----------- pgn.h | 112 +- piece.c | 406 ++++---- piece.h | 184 ++-- pipex_posix.c | 4 - polyglot.spec | 2 +- random.c | 462 ++++---- random.h | 62 +- san.c | 1134 ++++++++++---------- san.h | 44 +- search.c | 500 +++++----- search.h | 50 +- square.c | 492 +++++----- square.h | 276 +++--- uci.c | 1924 ++++++++++++++++---------------- uci.h | 218 ++-- util.c | 1052 +++++++++--------- util.h | 385 ++++---- xboard2uci.c | 3427 +++++++++++++++++++++++++++++---------------------------- xboard2uci.h | 48 +- 73 files changed, 15099 insertions(+), 15090 deletions(-) diff --git a/COPYING b/COPYING index 45645b4..5b6e7c6 100644 --- a/COPYING +++ b/COPYING @@ -1,340 +1,340 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) 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 -this service 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 make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. 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. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -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 -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE 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. - - 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 -convey 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 2 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision 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, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This 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 Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog index 9b2b2c4..b19706e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,231 +1,236 @@ -========1.4.61b================= -- uci_isready replaced by uci_isready_sync. Polyglot should not send commands to the engine while it is syncing. -========1.4.60b================= -- The result string after an illegal move now shows the actual attempted move. -========1.4.59b================= -- Bugfix: the changes in 1.4.57b created a regression where the input buffer of polyglot could overflow with engines producing lots of output very fast. -========1.4.58b================= -- Implementation of BookDepth in UCI mode. -- Small corrections to the manpage. -========1.4.57b================= -- First attempt at killing engines that do not react to "quit". -========1.4.56b================= -- Better handling of non-existing engine command on Linux. No changes on Windows. -=========1.4.55b================ -- Suppression of some error dialogs. -- Small delay in between final error message and actually quitting. -=========1.4.54b================ -- More graceful handling of engine crashes. -- New EngineCommand is now passed through wordexp on Linux. -=========1.4.53b================ -- Multipv code by HGM. -=========1.4.52b================ -- Reexport SyncStop. It is apparently necessary for the Aquarium Book Adapter. -=========1.4.51b================ -- Support for new nps command. Code provided by Harm Geert Muller. -=========1.4.50b================ -- Change in architecture. Persistence is disabled. The user is required to push the "Save" button explicitly to save the settings. What is retained is that in case PG is invoked with -noini (or as a special exception for WB 4.4.0 when the config files are polyglot_1st.ini or polyglot_2nd.ini) then PG uses a default config file whose name is derived from the engine name. -- New option: OnlyWbOptions (default: true). Restrict the options that PG sends to those that are potentially useful for WinBoard. -=========1.4.47b================ -- Try to detect if the engine is not an UCI engine. -=========1.4.46b================ -- The default persistence directory on Windows is now _PG. The names of the engine specific ini files are mangled so as not to contain spaces. -- PG now tries to guess if a string option is really a file or a path (like in the Arena GUI). -=========1.4.45b================ -- The engine specific config files (.ini) are now stored in a separate directory. $HOME/.polyglot on Linux and "./Polyglot Settings" on Windows. -- The engine specific config files are now complete config files. So they can be used in a stand alone fashion. -- Implemented a minor hack to make xboard show error messages during startup. -=========1.4.44b================ -- "Implementation" of new buttons and controls. -- The "Persist" option is now persistent. That is if you turn of "Persist" then as a special case PG will remember this. -- There is now a "reset" button which restores the default options. The code is commented out since WB does not support it yet. -=========1.4.42b================ -- SaveSettingsOnExit/SaveFile renamed as Persist/PersistFile. -- Many bug fixes in the persistence feature. -- The PG_.ini file now contains only options that have been changed. So the resulting ini files are much smaller. This makes this version of PG usable on WB 4.3.15 as now the engine specific ini file will be empty (the user has no way to change options). -=========1.4.41b================ -- Some segfaults fixed in case of corrupt config files. -- Persistence of options. If the option SaveSettingsOnExit is true (the default) PolyGlot now saves its options in a file whose name is given by the option SaveFile which by default is equal to the engine name, prefixex by PG_ and suffixed by ".ini". -=========1.4.39b================ -- Refactoring of config file parsing -- Fix crash bug in epd-test -- Do not export Chess960. This is handled completely internally. -- Do not export UCI_Opponent and UCI_Chess960. These are handled internally. -- PG can now also be comfortably configured through command line options (i.e. without using a config file). -- Allow quotes in configfile (as in Fonzy Bleumer's PG). -=========1.4.37b================ -- Two new options: BookDepth and BookTreshold. BookDepth limits the number of moves the book is used and BookTreshold sets the minimum weight a book move should have. -=========1.4.36b================ -- Bugfix: option = 0/1 was translated incorrectly. -- Default node count is 1. -- EOF received from the engine should now be logged correctly (i.e. after the buffer is empty). -- Bugfix: Nasty buffer overflow in the macro CONSTRUCT_ARG_STRING. -- Bugfix: pipex_writeln (win32) was logging at the wrong spot. -- Log board when an illegal move is received. -=========1.4.35b================ -- New WbWorkAround for silly bug in WB. Depth <=1 clears the engine output window. Why should an engine not be allowed to send info at depth one? -=========1.4.34b================ -- Warning: this release is less well tested as usual -- Allow spaces around "=" in "option =" commands. -- WbWorkArounds is now true by default. It decapitalizes Draw when this appears in engine option. -- Trying to set a non existent UCI option gives an error. -- PG will now resign in case of an illegal engine move. -- More code has been put in "pipex". -- info strings and unrecognized info lines are relayed to the GUI. -=========1.4.33b================ -- New option: "WbWorkArounds" to work around bugs in WB. Currently it blocks options which contain "Draw" in their name from being sent to the GUI. Engines that have such options are Rybka and HIARCS. -- Bugfix for ASSERT failure in bright. Now another ASSERT failure has appeared which seems to be bright's fault however. -=========1.4.32b================ -- Bugfix: the default setting for RepeatPV had become false again... -=========1.4.31b================ -- Bugfix: improper handling of vararg function. -=========1.4.30b================ -- Some more meaningful error messages added. -- Some buffer overflow checks added. -- Simplification of strange signal kludge in gui.c. -- Removal of obsolete code in engine.c and gui.c. Platform specific code has been abstracted and pushed into pipex_win32.c and pipex_posix.c -- The format of the version number has changed once again. Debian was unhappy with the previous one. -=========1.4b29================ -- Conversion from C++ to C (suggested by E.M.) -- More refactoring. The win32 and posix I/O now have a uniform interface (see pipex.h). -=========1.4b28================ -- Some comments added to explain the exact behaviour of some of the public functions in pipe.cpp. -- LineInput now returns a bool which is FALSE in case of EOF. -=========1.4b27================ -- Option "ScoreWhite" : report score from white's point of view (suggested by E.M.). -- Option "KibitzInterval" : try to wait this many seconds between kibitzes (suggested by E.M.) -=========1.4b26================ -- Contraction of version number. -- Log if SetProcessAffinityMask is not available (suggested by E.M.). -- pipe.cpp : Make PipeStruct a proper class with private/public members. -- Check for EOF in GUI input. -- pipe.cpp : delay reporting EOF until buffer is empty. -- Messages from the Engine to PG were not logged in the windows version. -=========1.4w10UCIb24=========== -- Portability fixes for WIN9X (Eric Mullins). -- Portability fixes for MSVC++ (Eric Mullins). -- Default setting of RepeatPV is now true. -- Do not read data if input buffer is full (Windows). -=========1.4w10UCIb22=========== -- Polyglot now completely poll free... -=========1.4w10UCIb21=========== -- Crash bug in memory command fixed -- Small optimizations -=========1.4w10UCIb20=========== -- More refactoring. -- No more polling for GUI input -=========1.4w10UCIb18=========== -- Two new utilities: info-book and dump-book. -=========1.4w10UCIb17=========== -- More refactoring. main.cpp is now #ifdef _WIN32 free. -- The main loop (previously in adapter.cpp) is now in its own file mainloop.cpp. -- adapter.cpp has been renamed into xboard2uci.cpp. It is #ifdef _WIN32 free. -- EOF from the engine no longer kills PG. It should now -be possible to close an engine and reopen another one (if that ever became useful) -=========1.4w10UCIb16=========== -- xboard options commands -- correction of handling of combo boxes in UCI protocol -- "gui-mode". It is now possible to run PG without config file -- The polyglot options are not exported, so they are now settable by the GUI -=========1.4w10UCIb15=========== -- Due to refactoring time stamps in Windows would be written twice. -This has been fixed. -- More refactoring; the number of #ifdef _WIN32's has again been -drastically reduced. -=========1.4w10UCIb14=========== -- option to alter priority now also works on windows -(Eric Mullins) -- refactoring so that posix and win32 part share more -code -- a number of potential busy loop scenarios have been eliminated -in the Windows code (Windows uses polling) -- the return value of CreateProcess is now checked -=========1.4w10UCIb13=========== -- perft mode exposed. -=========1.4w10UCIb12=========== -- Replaced %lld everywhere by S64_FORMAT. -=========1.4w10UCIb11=========== -- Crash bug fix (wrong parentheses in instruction that checked for help -option). -=========1.4w10UCIb10=========== -- It is now possible to do "make rpm" to make an rpm binary package. -- Trivial bug fixes. -- Documentation added for epd-test functionality (man page). -- Cosmetic cleanups of output of epd-test. -- "polyglot --help" output added. -- Added polyglot book format specification to distribution. -=========1.4w10UCIb9=========== -- Trivial cosmetic fixes -- Some engines do not support the "Hash" options. -So we do not send memory=1 in that case. -=========1.4w10UCIb8=========== -- Support for egtpath command in xboard protocol -=========1.4w10UCIb7=========== -- Debianization: it is now possible to do "make deb" to build a Debian/Ubuntu -package. -=========1.4w10UCIb6=========== -- UCI GUI support added. This makes it possible to use PG as a book engine -on GUI's like ChessBase and Arena which normally only support their -own proprietary format. - -- Support for new xboard "cores N" and "memory N" commands. See here -for a complete description - - http://home.hccnet.nl/h.g.muller/engine-intf.html - -- Some work arounds for engines like Toga which only allow some settings -to be set before the first "isready" command. - -- Autotooled distribution. - -- Proper manual page. The README file is generated automatically from this. - -- More sane naming of README files. - -- If BookLearn is false (the default) PG will open the book read only. - -- Windows and non-Windows log file formats are now the same. - -- Proper ChangeLog (you are reading it!). -=========1.4w10================ -fixed analysis output for toga -=========1.4w9================= -fixed bug in 1.4w8 -added RepeatPV workaround - fixed disappearing output in engine-output window while in multipv mode - when an engine sends its move to polyglot, - polyglot normally repeats the last pv string(which also contains score,depth and time usage) it got from the engine. - Some engines however do not send a new pv string just before sending the move and the now old pv string - find might confuse debugtools that parse the winboard debug files. - Adding "RepeatPV = false" to the [POLYGLOT] section of the ini file stops this repetition. - -=========1.4w8================= -fixed multipv output -note that the pv with the worst score will be on top of the engine-output window. -added timestamp in logfile (Jaap Weidemann) - -=========1.4w7================= -compiles under linux/unix again -=========1.4w6================= -access to winboard draw/drawoffer and resign - - 1:to activate draw offers the engine has - to define the "UCI_DrawOffers" parameter with the 'option" command at startup. - 2:to offer a draw or accept a draw offer:just send "info string DrawOffer" to polyglot. - 3:if winboard sends "draw" polyglot sends "setoption DrawOffer draw" to the engine. - 4.to resign: send "info string Resign" to polyglot. - please check the winboard documentation for the draw/drawoffer and resign commands. - -=========1.4w5:================ -Fixed errors in SyncStop handling. -book building: the error message now also contains the game number -added Affinity option: -In the [PolyGlot] section(ini file): -- "Affinity" mask -mask is a bit vector in which each bit represents the processors that a process is allowed to run on. - -some minor bugs fixed - -checks if child did really quit. - - +========1.4.63b================= +- Give ponder move as hint. +- Support for egtpath gaviota (this is a bit hacky right now). +========1.4.62b================= +- StringSize was not everywhere the same in Polyglot. This could lead to a buffer overflow in case of very long PV's. +========1.4.61b================= +- uci_isready replaced by uci_isready_sync. Polyglot should not send commands to the engine while it is syncing. +========1.4.60b================= +- The result string after an illegal move now shows the actual attempted move. +========1.4.59b================= +- Bugfix: the changes in 1.4.57b created a regression where the input buffer of polyglot could overflow with engines producing lots of output very fast. +========1.4.58b================= +- Implementation of BookDepth in UCI mode. +- Small corrections to the manpage. +========1.4.57b================= +- First attempt at killing engines that do not react to "quit". +========1.4.56b================= +- Better handling of non-existing engine command on Linux. No changes on Windows. +=========1.4.55b================ +- Suppression of some error dialogs. +- Small delay in between final error message and actually quitting. +=========1.4.54b================ +- More graceful handling of engine crashes. +- New EngineCommand is now passed through wordexp on Linux. +=========1.4.53b================ +- Multipv code by HGM. +=========1.4.52b================ +- Reexport SyncStop. It is apparently necessary for the Aquarium Book Adapter. +=========1.4.51b================ +- Support for new nps command. Code provided by Harm Geert Muller. +=========1.4.50b================ +- Change in architecture. Persistence is disabled. The user is required to push the "Save" button explicitly to save the settings. What is retained is that in case PG is invoked with -noini (or as a special exception for WB 4.4.0 when the config files are polyglot_1st.ini or polyglot_2nd.ini) then PG uses a default config file whose name is derived from the engine name. +- New option: OnlyWbOptions (default: true). Restrict the options that PG sends to those that are potentially useful for WinBoard. +=========1.4.47b================ +- Try to detect if the engine is not an UCI engine. +=========1.4.46b================ +- The default persistence directory on Windows is now _PG. The names of the engine specific ini files are mangled so as not to contain spaces. +- PG now tries to guess if a string option is really a file or a path (like in the Arena GUI). +=========1.4.45b================ +- The engine specific config files (.ini) are now stored in a separate directory. $HOME/.polyglot on Linux and "./Polyglot Settings" on Windows. +- The engine specific config files are now complete config files. So they can be used in a stand alone fashion. +- Implemented a minor hack to make xboard show error messages during startup. +=========1.4.44b================ +- "Implementation" of new buttons and controls. +- The "Persist" option is now persistent. That is if you turn of "Persist" then as a special case PG will remember this. +- There is now a "reset" button which restores the default options. The code is commented out since WB does not support it yet. +=========1.4.42b================ +- SaveSettingsOnExit/SaveFile renamed as Persist/PersistFile. +- Many bug fixes in the persistence feature. +- The PG_.ini file now contains only options that have been changed. So the resulting ini files are much smaller. This makes this version of PG usable on WB 4.3.15 as now the engine specific ini file will be empty (the user has no way to change options). +=========1.4.41b================ +- Some segfaults fixed in case of corrupt config files. +- Persistence of options. If the option SaveSettingsOnExit is true (the default) PolyGlot now saves its options in a file whose name is given by the option SaveFile which by default is equal to the engine name, prefixex by PG_ and suffixed by ".ini". +=========1.4.39b================ +- Refactoring of config file parsing +- Fix crash bug in epd-test +- Do not export Chess960. This is handled completely internally. +- Do not export UCI_Opponent and UCI_Chess960. These are handled internally. +- PG can now also be comfortably configured through command line options (i.e. without using a config file). +- Allow quotes in configfile (as in Fonzy Bleumer's PG). +=========1.4.37b================ +- Two new options: BookDepth and BookTreshold. BookDepth limits the number of moves the book is used and BookTreshold sets the minimum weight a book move should have. +=========1.4.36b================ +- Bugfix: option = 0/1 was translated incorrectly. +- Default node count is 1. +- EOF received from the engine should now be logged correctly (i.e. after the buffer is empty). +- Bugfix: Nasty buffer overflow in the macro CONSTRUCT_ARG_STRING. +- Bugfix: pipex_writeln (win32) was logging at the wrong spot. +- Log board when an illegal move is received. +=========1.4.35b================ +- New WbWorkAround for silly bug in WB. Depth <=1 clears the engine output window. Why should an engine not be allowed to send info at depth one? +=========1.4.34b================ +- Warning: this release is less well tested as usual +- Allow spaces around "=" in "option =" commands. +- WbWorkArounds is now true by default. It decapitalizes Draw when this appears in engine option. +- Trying to set a non existent UCI option gives an error. +- PG will now resign in case of an illegal engine move. +- More code has been put in "pipex". +- info strings and unrecognized info lines are relayed to the GUI. +=========1.4.33b================ +- New option: "WbWorkArounds" to work around bugs in WB. Currently it blocks options which contain "Draw" in their name from being sent to the GUI. Engines that have such options are Rybka and HIARCS. +- Bugfix for ASSERT failure in bright. Now another ASSERT failure has appeared which seems to be bright's fault however. +=========1.4.32b================ +- Bugfix: the default setting for RepeatPV had become false again... +=========1.4.31b================ +- Bugfix: improper handling of vararg function. +=========1.4.30b================ +- Some more meaningful error messages added. +- Some buffer overflow checks added. +- Simplification of strange signal kludge in gui.c. +- Removal of obsolete code in engine.c and gui.c. Platform specific code has been abstracted and pushed into pipex_win32.c and pipex_posix.c +- The format of the version number has changed once again. Debian was unhappy with the previous one. +=========1.4b29================ +- Conversion from C++ to C (suggested by E.M.) +- More refactoring. The win32 and posix I/O now have a uniform interface (see pipex.h). +=========1.4b28================ +- Some comments added to explain the exact behaviour of some of the public functions in pipe.cpp. +- LineInput now returns a bool which is FALSE in case of EOF. +=========1.4b27================ +- Option "ScoreWhite" : report score from white's point of view (suggested by E.M.). +- Option "KibitzInterval" : try to wait this many seconds between kibitzes (suggested by E.M.) +=========1.4b26================ +- Contraction of version number. +- Log if SetProcessAffinityMask is not available (suggested by E.M.). +- pipe.cpp : Make PipeStruct a proper class with private/public members. +- Check for EOF in GUI input. +- pipe.cpp : delay reporting EOF until buffer is empty. +- Messages from the Engine to PG were not logged in the windows version. +=========1.4w10UCIb24=========== +- Portability fixes for WIN9X (Eric Mullins). +- Portability fixes for MSVC++ (Eric Mullins). +- Default setting of RepeatPV is now true. +- Do not read data if input buffer is full (Windows). +=========1.4w10UCIb22=========== +- Polyglot now completely poll free... +=========1.4w10UCIb21=========== +- Crash bug in memory command fixed +- Small optimizations +=========1.4w10UCIb20=========== +- More refactoring. +- No more polling for GUI input +=========1.4w10UCIb18=========== +- Two new utilities: info-book and dump-book. +=========1.4w10UCIb17=========== +- More refactoring. main.cpp is now #ifdef _WIN32 free. +- The main loop (previously in adapter.cpp) is now in its own file mainloop.cpp. +- adapter.cpp has been renamed into xboard2uci.cpp. It is #ifdef _WIN32 free. +- EOF from the engine no longer kills PG. It should now +be possible to close an engine and reopen another one (if that ever became useful) +=========1.4w10UCIb16=========== +- xboard options commands +- correction of handling of combo boxes in UCI protocol +- "gui-mode". It is now possible to run PG without config file +- The polyglot options are not exported, so they are now settable by the GUI +=========1.4w10UCIb15=========== +- Due to refactoring time stamps in Windows would be written twice. +This has been fixed. +- More refactoring; the number of #ifdef _WIN32's has again been +drastically reduced. +=========1.4w10UCIb14=========== +- option to alter priority now also works on windows +(Eric Mullins) +- refactoring so that posix and win32 part share more +code +- a number of potential busy loop scenarios have been eliminated +in the Windows code (Windows uses polling) +- the return value of CreateProcess is now checked +=========1.4w10UCIb13=========== +- perft mode exposed. +=========1.4w10UCIb12=========== +- Replaced %lld everywhere by S64_FORMAT. +=========1.4w10UCIb11=========== +- Crash bug fix (wrong parentheses in instruction that checked for help +option). +=========1.4w10UCIb10=========== +- It is now possible to do "make rpm" to make an rpm binary package. +- Trivial bug fixes. +- Documentation added for epd-test functionality (man page). +- Cosmetic cleanups of output of epd-test. +- "polyglot --help" output added. +- Added polyglot book format specification to distribution. +=========1.4w10UCIb9=========== +- Trivial cosmetic fixes +- Some engines do not support the "Hash" options. +So we do not send memory=1 in that case. +=========1.4w10UCIb8=========== +- Support for egtpath command in xboard protocol +=========1.4w10UCIb7=========== +- Debianization: it is now possible to do "make deb" to build a Debian/Ubuntu +package. +=========1.4w10UCIb6=========== +- UCI GUI support added. This makes it possible to use PG as a book engine +on GUI's like ChessBase and Arena which normally only support their +own proprietary format. + +- Support for new xboard "cores N" and "memory N" commands. See here +for a complete description + + http://home.hccnet.nl/h.g.muller/engine-intf.html + +- Some work arounds for engines like Toga which only allow some settings +to be set before the first "isready" command. + +- Autotooled distribution. + +- Proper manual page. The README file is generated automatically from this. + +- More sane naming of README files. + +- If BookLearn is false (the default) PG will open the book read only. + +- Windows and non-Windows log file formats are now the same. + +- Proper ChangeLog (you are reading it!). +=========1.4w10================ +fixed analysis output for toga +=========1.4w9================= +fixed bug in 1.4w8 +added RepeatPV workaround + fixed disappearing output in engine-output window while in multipv mode + when an engine sends its move to polyglot, + polyglot normally repeats the last pv string(which also contains score,depth and time usage) it got from the engine. + Some engines however do not send a new pv string just before sending the move and the now old pv string + find might confuse debugtools that parse the winboard debug files. + Adding "RepeatPV = false" to the [POLYGLOT] section of the ini file stops this repetition. + +=========1.4w8================= +fixed multipv output +note that the pv with the worst score will be on top of the engine-output window. +added timestamp in logfile (Jaap Weidemann) + +=========1.4w7================= +compiles under linux/unix again +=========1.4w6================= +access to winboard draw/drawoffer and resign + + 1:to activate draw offers the engine has + to define the "UCI_DrawOffers" parameter with the 'option" command at startup. + 2:to offer a draw or accept a draw offer:just send "info string DrawOffer" to polyglot. + 3:if winboard sends "draw" polyglot sends "setoption DrawOffer draw" to the engine. + 4.to resign: send "info string Resign" to polyglot. + please check the winboard documentation for the draw/drawoffer and resign commands. + +=========1.4w5:================ +Fixed errors in SyncStop handling. +book building: the error message now also contains the game number +added Affinity option: +In the [PolyGlot] section(ini file): +- "Affinity" mask +mask is a bit vector in which each bit represents the processors that a process is allowed to run on. + +some minor bugs fixed + +checks if child did really quit. + + diff --git a/README1.3 b/README1.3 index fb06d38..5579315 100644 --- a/README1.3 +++ b/README1.3 @@ -1,434 +1,434 @@ - -Legal details -------------- - -PolyGlot 1.3 Copyright 2004-2005 Fabien Letouzey. - -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 2 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, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -USA - -See the file "copying.txt" for details. - - -General -------- - -PolyGlot 1.3 (2005/06/03). - -PolyGlot is a "UCI adapter". It connects a UCI chess engine to an -xboard interface such as WinBoard. UCI2WB is another such adapter -(for Windows). - -PolyGlot tries to solve known problems with other adapters. For -instance, it detects and reports draws by fifty-move rule, repetition, -etc ... - - -Official distribution URL -------------------------- - -The official distribution web site is Leo Dijksman's WBEC Ridderkerk: -http://wbec-ridderkerk.nl/ This is where you should be looking for -PolyGlot updates in the future. - - -Install -------- - -PolyGlot should have its own directory. The INI files for engines -should also be put there. Dirtier solutions are needed when -BookThinker is used though. - -On Windows the files "polyglot.exe" and "cygwin1.dll" (which you can -download from http://wbec-ridderkerk.nl/) are needed. On Linux and -Mac OS X only the file "polyglot_linux" or "polyglot_mac" is required. - - -Compiling ---------- - -The distribution comes up with Windows, Linux and Mac OS X binaries. -Compiling is therefore not necessary on those systems unless you want -to make a change in the program. In any case this section describes -the compiling procedure, it is safe to skip it. - -PolyGlot is a POSIX application (Unix compatible), and was developed -on Linux using g++ (the GNU C++ compiler). - -1) Unix - -You should be able to compile it on any POSIX-compliant operating -system (*not* Windows) with the following command line (or similar): - -> g++ -O2 -o polyglot *.cpp - -IMPORTANT: In "io.cpp", the variable "UseCR" should be set to "false". - -A Makefile is provided but might not work on your system ... - -2) Windows - -On Windows, you *must* use Cygnus GCC to compile PolyGlot. - -IMPORTANT: In "io.cpp", the variable "UseCR" should be set to "true". - - -Usage ------ - -PolyGlot acts as an xboard engine. There should be no difference with -a normal chess program as far as the interface (e.g. WinBoard) is -concerned. - -PolyGlot is invoked using "polyglot ". Note that PolyGlot -will look for the INI file in the current directory. If no -is given, "polyglot.ini" is selected. - -To use PolyGlot with XBoard, you would type something like this: -> xboard -fd 'polyglot_dir' -fcp 'polyglot engine.ini' - -Quotes are important when there is a space in the argument. - - -INI file --------- - -There should be a different INI file for each engine. Sections are -composed of "variable = value" lines. See the sample INI files in the -"example" directory. - -NOTE: There can be spaces in variable names or values. Do not use -quotes. - -1) [PolyGlot] section - -This section is used by PolyGlot only. The engine is unaware of these -options. The list of available options is detailed below in this -document. - -2) [Engine] section - -This section contains engine UCI options. PolyGlot does not -understand them, but sends the information to the engine at startup -(converted to UCI form). You can add any UCI option that makes sense -to the engine (not just the common options about hash-table size and -tablebases). - -NOTE: use INI syntax, not UCI. For example "OwnBook = true" is -correct. It will be replaced by PolyGlot with "setoption name OwnBook -value true" at engine startup. - -Standard UCI options are "Hash", "NalimovPath", "NalimovCache" and -"OwnBook". Hidden options like "Ponder" or "UCI_xxx" are automatic -and should not be put in an INI file. - -The other options are engine-specific. Check their name using a UCI -GUI or launch the engine in a console and type "uci". - - -Options -------- - -These should be put in the [PolyGlot] section. - -- "EngineName" (default: UCI name) - -This is the name that will appear in the xboard interface. It is -cosmetic only. You can use different names for tweaked versions of -the same engine. - -If no "Engine Name" is given, the UCI name will be used. - -- "EngineDir" (default: ".") - -Full path of the directory where the engine is installed. You can use -"." (without the quotes) if you know that PolyGlot will be launched in -the engine directory or the engine is in the "path" and does not need -any data file. - -- "EngineCommand" - -Put here the name of the engine executable file. You can also add -command-line arguments. Path searching is used and the current -directory will be "EngineDir". - -NOTE: Unix users are recommended to prepend "./"; this is required on -some secure systems. - -- "Log" (default: false) - -Whether PolyGlot should log all transactions with the interface and -the engine. This should be necessary only to locate problems. - -- "LogFile" - -The name of the log file. Note that it is put where PolyGlot was -launched from, not into the engine directory. - -WARNING: Log files are not cleared between sessions, and can become -very large. It is safe to remove them though. - -- "Resign" (default: false) - -Set this to "true" if you want PolyGlot to resign on behalf of the -engine. - -NOTE: Some engines display buggy scores from time to time although the -best move is correct. Use this option only if you know what you are -doing (e.g. you always check the final position of games). - -- "ResignMoves" (default: 3) - -Number of consecutive moves with "resign" score (see below) before -PolyGlot resigns for the engine. Positions with only one legal move -are ignored. - -- "ResignScore" (default: 600) - -This is the score in centipawns that will trigger resign "counting". - -- "ShowPonder" (*** NEW ***, default: true) - -Show search information during engine pondering. Turning this off -might be better for interactive use in some interfaces. - -- "KibitzMove" (*** NEW ***, default: false) - -Whether to kibitz when playing a move. - -- "KibitzPV" (*** NEW ***, default: false) - -Whether to kibitz when the PV is changed (new iteration or new best move). - -- "KibitzCommand" (*** NEW ***, default: "tellall") - -xboard command to use for kibitzing, normally "tellall" for kibitzing -or "tellothers" for whispering. - -- "KibitzDelay" (*** NEW ***, default: 5) - -How many seconds to wait before starting kibitzing. This has an -affect only if "KibitzPV" is selected, move kibitzes are always sent -regardless of the delay. - - -Work arounds ------------- - -Work arounds are identical to options except that they should be used -only when necessary. Their purpose is to try to hide problems with -various software (not just engines). The default value is always -correct for bug-free software. - -IMPORTANT: Any of these work arounds might be removed in future -versions of PolyGlot. You are strongly recommended to contact the -author of faulty software and truly fix the problem. - -In PolyGlot 1.3 there is only one optional work around: - -- "UCIVersion" (default: 2) - -The default value of 2 corresponds to UCI+. Use 1 to select plain -UCI for engines that have problems with UCI+. - - -Opening Book ------------- - -*** NEW *** - -PolyGlot 1.3 provides a minimal opening-book implementation. - -New options can be added to the [PolyGlot] section: - -- "Book" (default: false) - -Indicates whether a PolyGlot book should be used. This has no effect -on the engine own book (which can be controlled with the UCI option -"OwnBook" in the [Engine] section). In particular, it is possible to -use both a PolyGlot book and an engine book. In that case, the engine -book will be used whenever PolyGlot is out of book. Remember that -PolyGlot is unaware of whether the engine is itself using a book or -not. - -- "BookFile" - -The name of the (binary) book file. Note that PolyGlot will look for -it in the directory it was launched from, not in the engine directory. -Of course, full path can be used in which case the current directory -does not matter. - -Note that there is no option to control book usage. All parameters -are fixed when compiling a PGN file into a binary book (see below). -This is purposeful and is not likely to change. - -Using a book does not require any additional memory, this can be -important for memory-limited tournaments. - -A default book "fruit.bin" is provided in the archive. Note that this -book is very small and should probably not be used in serious games. -I hope that users will make other books available in the future. - - -Book Making ------------ - -*** NEW *** - -You can compile a PGN file into a binary book using PolyGlot on the -command line. At the moment, only a main (random) book is provided. -It is not yet possible to control opening lines manually. I am -working on it though. - -Usage: "polyglot make-book ". - -"make-book" options are: - -- "-pgn" - -Name of the input PGN file. PolyGlot should support any -standard-conforming file. Let me know if you encounter a problem. - -- "-bin" - -Name of the output binary file. I suggest ".bin" as the extension but -in fact PolyGlot does not care. - -- "-max-ply" (default: infinite) - -How many plies (half moves) to read for each game. E.g. if set to -"20", only the first 10 full moves of each game will be scanned. - -- "-min-game" (default: 3) - -How many times must a move be played to be kept in the book. In other -words, moves that were played too rarely will be left out. If you -scan full games "2" seems a minimum, but if you selected lines -manually "1" will make sense. - -Example: "polyglot make-book -pgn games.pgn -bin book.bin -max-ply 30". - -Building a book is usually very fast (a few minutes at most). Note -however that a lot of memory may be required. To reduce memory usage, -select a ply limit. - - -History -------- - -2004/04/30: PolyGlot 1.0 - -- first public release. - -2004/10/01: PolyGlot 1.1 - -- added "StartupWait" and "PonderWorkAround" ("AutoQuit" was available - in version 1.0 but not documented). - -- fixed a minor bug that could prevent "AutoQuit" from working with - some engines. - -2005/01/29: PolyGlot 1.2 - -- rewrote engine initialisation and UCI parsing to increase - UCI-standard compliance - -- added multi-move resign - -- added an internal work around for engines hanging with WinBoard - -2005/06/03: PolyGlot 1.3 - -- added opening book - -- added kibitzing - -- added "ShowPonder" option - - - -Known bugs ----------- - -*** IMPORTANT *** - -There is a bug (!) in the xboard automaton. The bug is related to -searching in draw positions (e.g. 50-move rule or repetition). I had -only been able to make PolyGlot crash by using analysis mode and -performing manual takebacks. I believe that this bug can only happen -in highly-interactive use (e.g. manual analysis). It is present in -all versions of PolyGlot, including this one. - -I attempted a work around in February. I vaguely remember the change -prevents crashing (not sure) but it is possible that PolyGlot now gets -stuck in some rare case, i.e. it refuses to produce a move. In any -case, the bug cannot occur silently, e.g. in a game that terminated -normally. - -Because of the small expected impact (nobody ever reported it to me) -and because fixing the bug would require a whole redesign of the -xboard module, I have no intention of working on it at the moment (!). - -Make sure to let me know if it appeared in any circounstance, thanks! -In particular if the bug ever occurs during a non-interactive session -(e.g. engine vs. engine game), then I will do something. - - -Thanks ------- - -Big thanks go to: - -- Dann Corbit for spending a lot of time compiling, testing, making - files available, etc ... - -- Leo Dijksman for hosting the PolyGlot distribution on his web site - (see Links) and also for thorough testing - -- Tord Romstad, Joshua Shriver and George Sobala for compiling and - testing on Mac OS X - -- users in the WinBoard forum for their feedback and encouraging - words: Roger Brown, Leo Dijksman, Igor Gorelikov, Mogens Larsen, - Volker Pittlik, Norm Pollock, Günther Simon and Salvo Spitaleri - in particular - - -Links ------ - -- Tim Mann's Chess Pages: http://www.tim-mann.org/xboard.html -- Leo Dijksman's WBEC Ridderkerk: http://wbec-ridderkerk.nl/ -- Volker Pittlik's Winboard Forum: http://wbforum.volker-pittlik.name/ - - -Contact me ----------- - -You can contact me at fabien_letouzey@hotmail.com - -If I am not available, you can discuss PolyGlot issues in Volker -Pittlik's Winboard Forum: http://wbforum.volker-pittlik.name/ - -In fact for questions regarding specific Windows-only engines, you are -advised to ask directly in the WinBoard forum, as I don't have Windows -myself. - - -The end -------- - -Fabien Letouzey, 2005/06/03. - + +Legal details +------------- + +PolyGlot 1.3 Copyright 2004-2005 Fabien Letouzey. + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA + +See the file "copying.txt" for details. + + +General +------- + +PolyGlot 1.3 (2005/06/03). + +PolyGlot is a "UCI adapter". It connects a UCI chess engine to an +xboard interface such as WinBoard. UCI2WB is another such adapter +(for Windows). + +PolyGlot tries to solve known problems with other adapters. For +instance, it detects and reports draws by fifty-move rule, repetition, +etc ... + + +Official distribution URL +------------------------- + +The official distribution web site is Leo Dijksman's WBEC Ridderkerk: +http://wbec-ridderkerk.nl/ This is where you should be looking for +PolyGlot updates in the future. + + +Install +------- + +PolyGlot should have its own directory. The INI files for engines +should also be put there. Dirtier solutions are needed when +BookThinker is used though. + +On Windows the files "polyglot.exe" and "cygwin1.dll" (which you can +download from http://wbec-ridderkerk.nl/) are needed. On Linux and +Mac OS X only the file "polyglot_linux" or "polyglot_mac" is required. + + +Compiling +--------- + +The distribution comes up with Windows, Linux and Mac OS X binaries. +Compiling is therefore not necessary on those systems unless you want +to make a change in the program. In any case this section describes +the compiling procedure, it is safe to skip it. + +PolyGlot is a POSIX application (Unix compatible), and was developed +on Linux using g++ (the GNU C++ compiler). + +1) Unix + +You should be able to compile it on any POSIX-compliant operating +system (*not* Windows) with the following command line (or similar): + +> g++ -O2 -o polyglot *.cpp + +IMPORTANT: In "io.cpp", the variable "UseCR" should be set to "false". + +A Makefile is provided but might not work on your system ... + +2) Windows + +On Windows, you *must* use Cygnus GCC to compile PolyGlot. + +IMPORTANT: In "io.cpp", the variable "UseCR" should be set to "true". + + +Usage +----- + +PolyGlot acts as an xboard engine. There should be no difference with +a normal chess program as far as the interface (e.g. WinBoard) is +concerned. + +PolyGlot is invoked using "polyglot ". Note that PolyGlot +will look for the INI file in the current directory. If no +is given, "polyglot.ini" is selected. + +To use PolyGlot with XBoard, you would type something like this: +> xboard -fd 'polyglot_dir' -fcp 'polyglot engine.ini' + +Quotes are important when there is a space in the argument. + + +INI file +-------- + +There should be a different INI file for each engine. Sections are +composed of "variable = value" lines. See the sample INI files in the +"example" directory. + +NOTE: There can be spaces in variable names or values. Do not use +quotes. + +1) [PolyGlot] section + +This section is used by PolyGlot only. The engine is unaware of these +options. The list of available options is detailed below in this +document. + +2) [Engine] section + +This section contains engine UCI options. PolyGlot does not +understand them, but sends the information to the engine at startup +(converted to UCI form). You can add any UCI option that makes sense +to the engine (not just the common options about hash-table size and +tablebases). + +NOTE: use INI syntax, not UCI. For example "OwnBook = true" is +correct. It will be replaced by PolyGlot with "setoption name OwnBook +value true" at engine startup. + +Standard UCI options are "Hash", "NalimovPath", "NalimovCache" and +"OwnBook". Hidden options like "Ponder" or "UCI_xxx" are automatic +and should not be put in an INI file. + +The other options are engine-specific. Check their name using a UCI +GUI or launch the engine in a console and type "uci". + + +Options +------- + +These should be put in the [PolyGlot] section. + +- "EngineName" (default: UCI name) + +This is the name that will appear in the xboard interface. It is +cosmetic only. You can use different names for tweaked versions of +the same engine. + +If no "Engine Name" is given, the UCI name will be used. + +- "EngineDir" (default: ".") + +Full path of the directory where the engine is installed. You can use +"." (without the quotes) if you know that PolyGlot will be launched in +the engine directory or the engine is in the "path" and does not need +any data file. + +- "EngineCommand" + +Put here the name of the engine executable file. You can also add +command-line arguments. Path searching is used and the current +directory will be "EngineDir". + +NOTE: Unix users are recommended to prepend "./"; this is required on +some secure systems. + +- "Log" (default: false) + +Whether PolyGlot should log all transactions with the interface and +the engine. This should be necessary only to locate problems. + +- "LogFile" + +The name of the log file. Note that it is put where PolyGlot was +launched from, not into the engine directory. + +WARNING: Log files are not cleared between sessions, and can become +very large. It is safe to remove them though. + +- "Resign" (default: false) + +Set this to "true" if you want PolyGlot to resign on behalf of the +engine. + +NOTE: Some engines display buggy scores from time to time although the +best move is correct. Use this option only if you know what you are +doing (e.g. you always check the final position of games). + +- "ResignMoves" (default: 3) + +Number of consecutive moves with "resign" score (see below) before +PolyGlot resigns for the engine. Positions with only one legal move +are ignored. + +- "ResignScore" (default: 600) + +This is the score in centipawns that will trigger resign "counting". + +- "ShowPonder" (*** NEW ***, default: true) + +Show search information during engine pondering. Turning this off +might be better for interactive use in some interfaces. + +- "KibitzMove" (*** NEW ***, default: false) + +Whether to kibitz when playing a move. + +- "KibitzPV" (*** NEW ***, default: false) + +Whether to kibitz when the PV is changed (new iteration or new best move). + +- "KibitzCommand" (*** NEW ***, default: "tellall") + +xboard command to use for kibitzing, normally "tellall" for kibitzing +or "tellothers" for whispering. + +- "KibitzDelay" (*** NEW ***, default: 5) + +How many seconds to wait before starting kibitzing. This has an +affect only if "KibitzPV" is selected, move kibitzes are always sent +regardless of the delay. + + +Work arounds +------------ + +Work arounds are identical to options except that they should be used +only when necessary. Their purpose is to try to hide problems with +various software (not just engines). The default value is always +correct for bug-free software. + +IMPORTANT: Any of these work arounds might be removed in future +versions of PolyGlot. You are strongly recommended to contact the +author of faulty software and truly fix the problem. + +In PolyGlot 1.3 there is only one optional work around: + +- "UCIVersion" (default: 2) + +The default value of 2 corresponds to UCI+. Use 1 to select plain +UCI for engines that have problems with UCI+. + + +Opening Book +------------ + +*** NEW *** + +PolyGlot 1.3 provides a minimal opening-book implementation. + +New options can be added to the [PolyGlot] section: + +- "Book" (default: false) + +Indicates whether a PolyGlot book should be used. This has no effect +on the engine own book (which can be controlled with the UCI option +"OwnBook" in the [Engine] section). In particular, it is possible to +use both a PolyGlot book and an engine book. In that case, the engine +book will be used whenever PolyGlot is out of book. Remember that +PolyGlot is unaware of whether the engine is itself using a book or +not. + +- "BookFile" + +The name of the (binary) book file. Note that PolyGlot will look for +it in the directory it was launched from, not in the engine directory. +Of course, full path can be used in which case the current directory +does not matter. + +Note that there is no option to control book usage. All parameters +are fixed when compiling a PGN file into a binary book (see below). +This is purposeful and is not likely to change. + +Using a book does not require any additional memory, this can be +important for memory-limited tournaments. + +A default book "fruit.bin" is provided in the archive. Note that this +book is very small and should probably not be used in serious games. +I hope that users will make other books available in the future. + + +Book Making +----------- + +*** NEW *** + +You can compile a PGN file into a binary book using PolyGlot on the +command line. At the moment, only a main (random) book is provided. +It is not yet possible to control opening lines manually. I am +working on it though. + +Usage: "polyglot make-book ". + +"make-book" options are: + +- "-pgn" + +Name of the input PGN file. PolyGlot should support any +standard-conforming file. Let me know if you encounter a problem. + +- "-bin" + +Name of the output binary file. I suggest ".bin" as the extension but +in fact PolyGlot does not care. + +- "-max-ply" (default: infinite) + +How many plies (half moves) to read for each game. E.g. if set to +"20", only the first 10 full moves of each game will be scanned. + +- "-min-game" (default: 3) + +How many times must a move be played to be kept in the book. In other +words, moves that were played too rarely will be left out. If you +scan full games "2" seems a minimum, but if you selected lines +manually "1" will make sense. + +Example: "polyglot make-book -pgn games.pgn -bin book.bin -max-ply 30". + +Building a book is usually very fast (a few minutes at most). Note +however that a lot of memory may be required. To reduce memory usage, +select a ply limit. + + +History +------- + +2004/04/30: PolyGlot 1.0 + +- first public release. + +2004/10/01: PolyGlot 1.1 + +- added "StartupWait" and "PonderWorkAround" ("AutoQuit" was available + in version 1.0 but not documented). + +- fixed a minor bug that could prevent "AutoQuit" from working with + some engines. + +2005/01/29: PolyGlot 1.2 + +- rewrote engine initialisation and UCI parsing to increase + UCI-standard compliance + +- added multi-move resign + +- added an internal work around for engines hanging with WinBoard + +2005/06/03: PolyGlot 1.3 + +- added opening book + +- added kibitzing + +- added "ShowPonder" option + + + +Known bugs +---------- + +*** IMPORTANT *** + +There is a bug (!) in the xboard automaton. The bug is related to +searching in draw positions (e.g. 50-move rule or repetition). I had +only been able to make PolyGlot crash by using analysis mode and +performing manual takebacks. I believe that this bug can only happen +in highly-interactive use (e.g. manual analysis). It is present in +all versions of PolyGlot, including this one. + +I attempted a work around in February. I vaguely remember the change +prevents crashing (not sure) but it is possible that PolyGlot now gets +stuck in some rare case, i.e. it refuses to produce a move. In any +case, the bug cannot occur silently, e.g. in a game that terminated +normally. + +Because of the small expected impact (nobody ever reported it to me) +and because fixing the bug would require a whole redesign of the +xboard module, I have no intention of working on it at the moment (!). + +Make sure to let me know if it appeared in any circounstance, thanks! +In particular if the bug ever occurs during a non-interactive session +(e.g. engine vs. engine game), then I will do something. + + +Thanks +------ + +Big thanks go to: + +- Dann Corbit for spending a lot of time compiling, testing, making + files available, etc ... + +- Leo Dijksman for hosting the PolyGlot distribution on his web site + (see Links) and also for thorough testing + +- Tord Romstad, Joshua Shriver and George Sobala for compiling and + testing on Mac OS X + +- users in the WinBoard forum for their feedback and encouraging + words: Roger Brown, Leo Dijksman, Igor Gorelikov, Mogens Larsen, + Volker Pittlik, Norm Pollock, Günther Simon and Salvo Spitaleri + in particular + + +Links +----- + +- Tim Mann's Chess Pages: http://www.tim-mann.org/xboard.html +- Leo Dijksman's WBEC Ridderkerk: http://wbec-ridderkerk.nl/ +- Volker Pittlik's Winboard Forum: http://wbforum.volker-pittlik.name/ + + +Contact me +---------- + +You can contact me at fabien_letouzey@hotmail.com + +If I am not available, you can discuss PolyGlot issues in Volker +Pittlik's Winboard Forum: http://wbforum.volker-pittlik.name/ + +In fact for questions regarding specific Windows-only engines, you are +advised to ask directly in the WinBoard forum, as I don't have Windows +myself. + + +The end +------- + +Fabien Letouzey, 2005/06/03. + diff --git a/README1.4w b/README1.4w index 1567e9f..6deb7b8 100644 --- a/README1.4w +++ b/README1.4w @@ -1,69 +1,69 @@ -=== PolyGlot 1.4W ==== -Polyglot 1.4W is a modified polyglot 1.4 from Fabien Letouzy. -Just like polyglot 1.3w(see below) it can be compiled and run under windows without -the need for a cygwin1.dll - -Best -Fonzy -www.geenvis.net -=========1.4w10================ -fixed analysis output for toga -=========1.4w9================= -fixed bug in 1.4w8 -added RepeatPV workaround - fixed disappearing output in engine-output window while in multipv mode - when an engine sends its move to polyglot, - polyglot normally repeats the last pv string(which also contains score,depth and time usage) it got from the engine. - Some engines however do not send a new pv string just before sending the move and the now old pv string - find might confuse debugtools that parse the winboard debug files. - Adding "RepeatPV = false" to the [POLYGLOT] section of the ini file stops this repetition. - -=========1.4w8================= -fixed multipv output -note that the pv with the worst score will be on top of the engine-output window. -added timestamp in logfile (Jaap Weidemann) - -=========1.4w7================= -compiles under linux/unix again -=========1.4w6================= -access to winboard draw/drawoffer and resign - - 1:to activate draw offers the engine has - to define the "UCI_DrawOffers" parameter with the 'option" command at startup. - 2:to offer a draw or accept a draw offer:just send "info string DrawOffer" to polyglot. - 3:if winboard sends "draw" polyglot sends "setoption DrawOffer draw" to the engine. - 4.to resign: send "info string Resign" to polyglot. - please check the winboard documentation for the draw/drawoffer and resign commands. - -=========1.4w5:================ -Fixed errors in SyncStop handling. -book building: the error message now also contains the game number -added Affinity option: -In the [PolyGlot] section(ini file): -- "Affinity" mask -mask is a bit vector in which each bit represents the processors that a process is allowed to run on. - -some minor bugs fixed - -checks if child did really quit. - -********************************************************* -=== PolyGlot 1.3W ReadMe === - -PolyGlot - a UCI-to-WinBoard Adapter for UCI Chess Engines -Designed by Fabien Letouzey and Morning Yellow -Version: 1.3W, Last Modified: Jan. 2006 - -PolyGlot 1.3W is the modified version of 1.3 by Fabien Letouzey, -which can be compiled and run under Windows without CygWin. - -The version of 1.3W has the following modifications: -1. Added a module, "pipe.h/pipe.cpp". -2. Removed two modules, "io.h/io.cpp" and "engine.h/engine.cpp". -3. Modified all statements related on these modules. -4. fixed "Move Now" (the bug fixed in PolyGlot 1.4). - -PolyGlot 1.3W can be downloaded from: -http://www.elephantbase.net/download/polyglot.rar -For information of "PolyGlot 1.3", see "readme.txt" -For legal information, see "copying.txt" +=== PolyGlot 1.4W ==== +Polyglot 1.4W is a modified polyglot 1.4 from Fabien Letouzy. +Just like polyglot 1.3w(see below) it can be compiled and run under windows without +the need for a cygwin1.dll + +Best +Fonzy +www.geenvis.net +=========1.4w10================ +fixed analysis output for toga +=========1.4w9================= +fixed bug in 1.4w8 +added RepeatPV workaround + fixed disappearing output in engine-output window while in multipv mode + when an engine sends its move to polyglot, + polyglot normally repeats the last pv string(which also contains score,depth and time usage) it got from the engine. + Some engines however do not send a new pv string just before sending the move and the now old pv string + find might confuse debugtools that parse the winboard debug files. + Adding "RepeatPV = false" to the [POLYGLOT] section of the ini file stops this repetition. + +=========1.4w8================= +fixed multipv output +note that the pv with the worst score will be on top of the engine-output window. +added timestamp in logfile (Jaap Weidemann) + +=========1.4w7================= +compiles under linux/unix again +=========1.4w6================= +access to winboard draw/drawoffer and resign + + 1:to activate draw offers the engine has + to define the "UCI_DrawOffers" parameter with the 'option" command at startup. + 2:to offer a draw or accept a draw offer:just send "info string DrawOffer" to polyglot. + 3:if winboard sends "draw" polyglot sends "setoption DrawOffer draw" to the engine. + 4.to resign: send "info string Resign" to polyglot. + please check the winboard documentation for the draw/drawoffer and resign commands. + +=========1.4w5:================ +Fixed errors in SyncStop handling. +book building: the error message now also contains the game number +added Affinity option: +In the [PolyGlot] section(ini file): +- "Affinity" mask +mask is a bit vector in which each bit represents the processors that a process is allowed to run on. + +some minor bugs fixed + +checks if child did really quit. + +********************************************************* +=== PolyGlot 1.3W ReadMe === + +PolyGlot - a UCI-to-WinBoard Adapter for UCI Chess Engines +Designed by Fabien Letouzey and Morning Yellow +Version: 1.3W, Last Modified: Jan. 2006 + +PolyGlot 1.3W is the modified version of 1.3 by Fabien Letouzey, +which can be compiled and run under Windows without CygWin. + +The version of 1.3W has the following modifications: +1. Added a module, "pipe.h/pipe.cpp". +2. Removed two modules, "io.h/io.cpp" and "engine.h/engine.cpp". +3. Modified all statements related on these modules. +4. fixed "Move Now" (the bug fixed in PolyGlot 1.4). + +PolyGlot 1.3W can be downloaded from: +http://www.elephantbase.net/download/polyglot.rar +For information of "PolyGlot 1.3", see "readme.txt" +For legal information, see "copying.txt" diff --git a/attack.c b/attack.c index ecaa14a..2f9b571 100644 --- a/attack.c +++ b/attack.c @@ -1,224 +1,224 @@ - -// attack.c - -// includes - -#include "board.h" -#include "colour.h" -#include "move.h" -#include "attack.h" -#include "piece.h" -#include "util.h" - -// macros - -#define DELTA_INC(delta) (DeltaInc[128+(delta)]) -#define DELTA_MASK(delta) (DeltaMask[128+(delta)]) - -// "constants" - -const sint8 KnightInc[8+1] = { - -33, -31, -18, -14, +14, +18, +31, +33, 0 -}; - -const sint8 BishopInc[4+1] = { - -17, -15, +15, +17, 0 -}; - -const sint8 RookInc[4+1] = { - -16, -1, +1, +16, 0 -}; - -const sint8 QueenInc[8+1] = { - -17, -16, -15, -1, +1, +15, +16, +17, 0 -}; - -const sint8 KingInc[8+1] = { - -17, -16, -15, -1, +1, +15, +16, +17, 0 -}; - -// variables - -static sint8 DeltaInc[256]; -static uint8 DeltaMask[256]; - -// prototypes - -static bool delta_is_ok (int delta); -static bool inc_is_ok (int inc); - -// functions - -// attack_init() - -void attack_init() { - - int delta; - int dir, inc, dist; - - for (delta = -128; delta < +128; delta++) { - DeltaInc[128+delta] = IncNone; - DeltaMask[128+delta] = 0; - } - - DeltaMask[128-17] |= BlackPawnFlag; - DeltaMask[128-15] |= BlackPawnFlag; - - DeltaMask[128+15] |= WhitePawnFlag; - DeltaMask[128+17] |= WhitePawnFlag; - - for (dir = 0; dir < 8; dir++) { - delta = KnightInc[dir]; - ASSERT(delta_is_ok(delta)); - DeltaMask[128+delta] |= KnightFlag; - } - - for (dir = 0; dir < 4; dir++) { - inc = BishopInc[dir]; - ASSERT(inc!=IncNone); - for (dist = 1; dist < 8; dist++) { - delta = inc*dist; - ASSERT(delta_is_ok(delta)); - ASSERT(DeltaInc[128+delta]==IncNone); - DeltaInc[128+delta] = inc; - DeltaMask[128+delta] |= BishopFlag; - } - } - - for (dir = 0; dir < 4; dir++) { - inc = RookInc[dir]; - ASSERT(inc!=IncNone); - for (dist = 1; dist < 8; dist++) { - delta = inc*dist; - ASSERT(delta_is_ok(delta)); - ASSERT(DeltaInc[128+delta]==IncNone); - DeltaInc[128+delta] = inc; - DeltaMask[128+delta] |= RookFlag; - } - } - - for (dir = 0; dir < 8; dir++) { - delta = KingInc[dir]; - ASSERT(delta_is_ok(delta)); - DeltaMask[128+delta] |= KingFlag; - } -} - -// delta_is_ok() - -static bool delta_is_ok(int delta) { - - if (delta < -119 || delta > +119) return FALSE; - - return TRUE; -} - -// inc_is_ok() - -static bool inc_is_ok(int inc) { - - int dir; - - for (dir = 0; dir < 8; dir++) { - if (KingInc[dir] == inc) return TRUE; - } - - return FALSE; -} - -// is_in_check() - -bool is_in_check(const board_t * board, int colour) { - - ASSERT(board_is_ok(board)); - ASSERT(colour_is_ok(colour)); - - return is_attacked(board,king_pos(board,colour),colour_opp(colour)); -} - -// is_attacked() - -bool is_attacked(const board_t * board, int to, int colour) { - - const uint8 * ptr; - int from, piece; - - ASSERT(board_is_ok(board)); - ASSERT(square_is_ok(to)); - ASSERT(colour_is_ok(colour)); - - for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { - - piece = board->square[from]; - ASSERT(colour_equal(piece,colour)); - - if (piece_attack(board,piece,from,to)) return TRUE; - } - - return FALSE; -} - -// piece_attack() - -bool piece_attack(const board_t * board, int piece, int from, int to) { - - int delta; - int inc, sq; - - ASSERT(board_is_ok(board)); - ASSERT(piece_is_ok(piece)); - ASSERT(square_is_ok(from)); - ASSERT(square_is_ok(to)); - - delta = to - from; - ASSERT(delta_is_ok(delta)); - - if ((piece & DELTA_MASK(delta)) == 0) return FALSE; // no pseudo-attack - - if (!piece_is_slider(piece)) return TRUE; - - inc = DELTA_INC(delta); - ASSERT(inc_is_ok(inc)); - - for (sq = from+inc; sq != to; sq += inc) { - ASSERT(square_is_ok(sq)); - if (board->square[sq] != Empty) return FALSE; // blocker - } - - return TRUE; -} - -// is_pinned() - -bool is_pinned(const board_t * board, int from, int to, int colour) { - - int king; - int inc; - int sq, piece; - - ASSERT(board!=NULL); - ASSERT(square_is_ok(from)); - ASSERT(square_is_ok(to)); - ASSERT(colour_is_ok(colour)); - - king = king_pos(board,colour); - - inc = DELTA_INC(king-from); - if (inc == IncNone) return FALSE; // not a line - - sq = from; - do sq += inc; while (board->square[sq] == Empty); - - if (sq != king) return FALSE; // blocker - - sq = from; - do sq -= inc; while ((piece=board->square[sq]) == Empty); - - return square_is_ok(sq) - && (piece & DELTA_MASK(king-sq)) != 0 - && piece_colour(piece) == colour_opp(colour) - && DELTA_INC(king-to) != inc; -} - -// end of attack.cpp - + +// attack.c + +// includes + +#include "board.h" +#include "colour.h" +#include "move.h" +#include "attack.h" +#include "piece.h" +#include "util.h" + +// macros + +#define DELTA_INC(delta) (DeltaInc[128+(delta)]) +#define DELTA_MASK(delta) (DeltaMask[128+(delta)]) + +// "constants" + +const sint8 KnightInc[8+1] = { + -33, -31, -18, -14, +14, +18, +31, +33, 0 +}; + +const sint8 BishopInc[4+1] = { + -17, -15, +15, +17, 0 +}; + +const sint8 RookInc[4+1] = { + -16, -1, +1, +16, 0 +}; + +const sint8 QueenInc[8+1] = { + -17, -16, -15, -1, +1, +15, +16, +17, 0 +}; + +const sint8 KingInc[8+1] = { + -17, -16, -15, -1, +1, +15, +16, +17, 0 +}; + +// variables + +static sint8 DeltaInc[256]; +static uint8 DeltaMask[256]; + +// prototypes + +static bool delta_is_ok (int delta); +static bool inc_is_ok (int inc); + +// functions + +// attack_init() + +void attack_init() { + + int delta; + int dir, inc, dist; + + for (delta = -128; delta < +128; delta++) { + DeltaInc[128+delta] = IncNone; + DeltaMask[128+delta] = 0; + } + + DeltaMask[128-17] |= BlackPawnFlag; + DeltaMask[128-15] |= BlackPawnFlag; + + DeltaMask[128+15] |= WhitePawnFlag; + DeltaMask[128+17] |= WhitePawnFlag; + + for (dir = 0; dir < 8; dir++) { + delta = KnightInc[dir]; + ASSERT(delta_is_ok(delta)); + DeltaMask[128+delta] |= KnightFlag; + } + + for (dir = 0; dir < 4; dir++) { + inc = BishopInc[dir]; + ASSERT(inc!=IncNone); + for (dist = 1; dist < 8; dist++) { + delta = inc*dist; + ASSERT(delta_is_ok(delta)); + ASSERT(DeltaInc[128+delta]==IncNone); + DeltaInc[128+delta] = inc; + DeltaMask[128+delta] |= BishopFlag; + } + } + + for (dir = 0; dir < 4; dir++) { + inc = RookInc[dir]; + ASSERT(inc!=IncNone); + for (dist = 1; dist < 8; dist++) { + delta = inc*dist; + ASSERT(delta_is_ok(delta)); + ASSERT(DeltaInc[128+delta]==IncNone); + DeltaInc[128+delta] = inc; + DeltaMask[128+delta] |= RookFlag; + } + } + + for (dir = 0; dir < 8; dir++) { + delta = KingInc[dir]; + ASSERT(delta_is_ok(delta)); + DeltaMask[128+delta] |= KingFlag; + } +} + +// delta_is_ok() + +static bool delta_is_ok(int delta) { + + if (delta < -119 || delta > +119) return FALSE; + + return TRUE; +} + +// inc_is_ok() + +static bool inc_is_ok(int inc) { + + int dir; + + for (dir = 0; dir < 8; dir++) { + if (KingInc[dir] == inc) return TRUE; + } + + return FALSE; +} + +// is_in_check() + +bool is_in_check(const board_t * board, int colour) { + + ASSERT(board_is_ok(board)); + ASSERT(colour_is_ok(colour)); + + return is_attacked(board,king_pos(board,colour),colour_opp(colour)); +} + +// is_attacked() + +bool is_attacked(const board_t * board, int to, int colour) { + + const uint8 * ptr; + int from, piece; + + ASSERT(board_is_ok(board)); + ASSERT(square_is_ok(to)); + ASSERT(colour_is_ok(colour)); + + for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { + + piece = board->square[from]; + ASSERT(colour_equal(piece,colour)); + + if (piece_attack(board,piece,from,to)) return TRUE; + } + + return FALSE; +} + +// piece_attack() + +bool piece_attack(const board_t * board, int piece, int from, int to) { + + int delta; + int inc, sq; + + ASSERT(board_is_ok(board)); + ASSERT(piece_is_ok(piece)); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + + delta = to - from; + ASSERT(delta_is_ok(delta)); + + if ((piece & DELTA_MASK(delta)) == 0) return FALSE; // no pseudo-attack + + if (!piece_is_slider(piece)) return TRUE; + + inc = DELTA_INC(delta); + ASSERT(inc_is_ok(inc)); + + for (sq = from+inc; sq != to; sq += inc) { + ASSERT(square_is_ok(sq)); + if (board->square[sq] != Empty) return FALSE; // blocker + } + + return TRUE; +} + +// is_pinned() + +bool is_pinned(const board_t * board, int from, int to, int colour) { + + int king; + int inc; + int sq, piece; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + ASSERT(colour_is_ok(colour)); + + king = king_pos(board,colour); + + inc = DELTA_INC(king-from); + if (inc == IncNone) return FALSE; // not a line + + sq = from; + do sq += inc; while (board->square[sq] == Empty); + + if (sq != king) return FALSE; // blocker + + sq = from; + do sq -= inc; while ((piece=board->square[sq]) == Empty); + + return square_is_ok(sq) + && (piece & DELTA_MASK(king-sq)) != 0 + && piece_colour(piece) == colour_opp(colour) + && DELTA_INC(king-to) != inc; +} + +// end of attack.cpp + diff --git a/attack.h b/attack.h index c111cdc..e59fe43 100644 --- a/attack.h +++ b/attack.h @@ -1,37 +1,37 @@ - -// attack.h - -#ifndef ATTACK_H -#define ATTACK_H - -// includes - -#include "board.h" -#include "util.h" - -// defines - -#define IncNone 0 - -// "constants" - -extern const sint8 KnightInc[8+1]; -extern const sint8 BishopInc[4+1]; -extern const sint8 RookInc[4+1]; -extern const sint8 QueenInc[8+1]; -extern const sint8 KingInc[8+1]; - -// functions - -extern void attack_init (); - -extern bool is_in_check (const board_t * board, int colour); -extern bool is_attacked (const board_t * board, int to, int colour); -extern bool piece_attack (const board_t * board, int piece, int from, int to); - -extern bool is_pinned (const board_t * board, int from, int to, int colour); - -#endif // !defined ATTACK_H - -// end of attack.h - + +// attack.h + +#ifndef ATTACK_H +#define ATTACK_H + +// includes + +#include "board.h" +#include "util.h" + +// defines + +#define IncNone 0 + +// "constants" + +extern const sint8 KnightInc[8+1]; +extern const sint8 BishopInc[4+1]; +extern const sint8 RookInc[4+1]; +extern const sint8 QueenInc[8+1]; +extern const sint8 KingInc[8+1]; + +// functions + +extern void attack_init (); + +extern bool is_in_check (const board_t * board, int colour); +extern bool is_attacked (const board_t * board, int to, int colour); +extern bool piece_attack (const board_t * board, int piece, int from, int to); + +extern bool is_pinned (const board_t * board, int from, int to, int colour); + +#endif // !defined ATTACK_H + +// end of attack.h + diff --git a/board.c b/board.c index 8c51a88..4f1139f 100644 --- a/board.c +++ b/board.c @@ -1,492 +1,492 @@ - -// board.c - -// includes - -#include - -#include "attack.h" -#include "board.h" -#include "colour.h" -#include "fen.h" -#include "hash.h" -#include "list.h" -#include "move.h" -#include "move_do.h" -#include "move_gen.h" -#include "move_legal.h" -#include "piece.h" -#include "util.h" - -// constants - -static const bool UseSlowDebug = FALSE; - -// functions - -// board_is_ok() - -bool board_is_ok(const board_t * board) { - - int sq, piece; - int colour, pos; - int king, rook; - - if (board == NULL) return FALSE; - - // optional heavy DEBUG mode - - if (!UseSlowDebug) return TRUE; - - // squares - - for (sq = 0; sq < SquareNb; sq++) { - piece = board->square[sq]; - if (square_is_ok(sq)) { - pos = board->pos[sq]; - if (piece == Empty) { - if (pos != -1) return FALSE; - } else { - if (pos < 0) return FALSE; - if (board->list[piece_colour(piece)][pos] != sq) return FALSE; - } - } else { - if (piece != Knight64) return FALSE; - } - } - - // white piece list - - colour = White; - pos = 0; - - if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE; - - sq = board->list[colour][pos]; - if (sq == SquareNone) return FALSE; - if (board->pos[sq] != pos) return FALSE; - piece = board->square[sq]; - if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE; - - for (pos++; pos < board->list_size[colour]; pos++) { - sq = board->list[colour][pos]; - if (sq == SquareNone) return FALSE; - if (board->pos[sq] != pos) return FALSE; - if (!colour_equal(board->square[sq],colour)) return FALSE; - } - - sq = board->list[colour][pos]; - if (sq != SquareNone) return FALSE; - - // black piece list - - colour = Black; - pos = 0; - - if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE; - - sq = board->list[colour][pos]; - if (sq == SquareNone) return FALSE; - if (board->pos[sq] != pos) return FALSE; - piece = board->square[sq]; - if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE; - - for (pos++; pos < board->list_size[colour]; pos++) { - sq = board->list[colour][pos]; - if (sq == SquareNone) return FALSE; - if (board->pos[sq] != pos) return FALSE; - if (!colour_equal(board->square[sq],colour)) return FALSE; - } - - sq = board->list[colour][pos]; - if (sq != SquareNone) return FALSE; - - // TODO: material - - if (board->number[WhiteKing12] != 1) return FALSE; - if (board->number[BlackKing12] != 1) return FALSE; - - if (!colour_is_ok(board->turn)) return FALSE; - - // castling status - - if (board->castle[White][SideH] != SquareNone) { - - king = board->list[White][0]; - if ((king < A1) || (king > H1)) return FALSE; - if (board->square[king] != WhiteKing256) return FALSE; - - rook = board->castle[White][SideH]; - if ((rook < A1) || (rook > H1)) return FALSE; - if (board->square[rook] != WhiteRook256) return FALSE; - - if (rook <= king) return FALSE; - } - - if (board->castle[White][SideA] != SquareNone) { - - king = board->list[White][0]; - if ((king < A1) || (king > H1)) return FALSE; - if (board->square[king] != WhiteKing256) return FALSE; - - rook = board->castle[White][SideA]; - if ((rook < A1) || (rook > H1)) return FALSE; - if (board->square[rook] != WhiteRook256) return FALSE; - - if (rook >= king) return FALSE; - } - - if (board->castle[Black][SideH] != SquareNone) { - - king = board->list[Black][0]; - if ((king < A8) || (king > H8)) return FALSE; - if (board->square[king] != BlackKing256) return FALSE; - - rook = board->castle[Black][SideH]; - if ((rook < A8) || (rook > H8)) return FALSE; - if (board->square[rook] != BlackRook256) return FALSE; - - if (rook <= king) return FALSE; - } - - if (board->castle[Black][SideA] != SquareNone) { - - king = board->list[Black][0]; - if (king < A8 || king > H8) return FALSE; - if (board->square[king] != BlackKing256) return FALSE; - - rook = board->castle[Black][SideA]; - if (rook < A8 || rook > H8) return FALSE; - if (board->square[rook] != BlackRook256) return FALSE; - - if (rook >= king) return FALSE; - } - - return TRUE; -} - -// board_clear() - -void board_clear(board_t * board) { - - int file, rank, sq; - int colour, pos; - int piece; - - ASSERT(board!=NULL); - - // edge squares - - for (sq = 0; sq < SquareNb; sq++) { - board->square[sq] = Knight64; // HACK: uncoloured knight - board->pos[sq] = -1; - } - - // empty squares - - for (rank = 0; rank < 8; rank++) { - for (file = 0; file < 8; file++) { - sq = square_make(file,rank); - board->square[sq] = Empty; - } - } - - // piece lists - - for (colour = 0; colour < 3; colour++) { - for (pos = 0; pos < 32; pos++) { // HACK - board->list[colour][pos] = SquareNone; - } - board->list_size[colour] = 0; - } - - // material - - for (piece = 0; piece < 12; piece++) { - board->number[piece] = 0; - } - - // rest - - board->turn = ColourNone; - board->castle[White][SideH] = SquareNone; - board->castle[White][SideA] = SquareNone; - board->castle[Black][SideH] = SquareNone; - board->castle[Black][SideA] = SquareNone; - board->ep_square = SquareNone; - - board->ply_nb = 0; - board->move_nb = 0; - - board->key = 0; -} - -// board_start() - -void board_start(board_t * board) { - - ASSERT(board!=NULL); - - if (!board_from_fen(board,StartFen)) ASSERT(FALSE); -} - -// board_copy() - -void board_copy(board_t * dst, const board_t * src) { - - ASSERT(dst!=NULL); - ASSERT(board_is_ok(src)); - - *dst = *src; -} - -// board_equal() - -bool board_equal(const board_t * board_1, const board_t * board_2) { - - int sq_64, sq; - - ASSERT(board_is_ok(board_1)); - ASSERT(board_is_ok(board_2)); - - // fast comparison - - if (board_1->key != board_2->key) return FALSE; - - // slow comparison - - for (sq_64 = 0; sq_64 < 64; sq_64++) { - sq = square_from_64(sq_64); - if (board_1->square[sq] != board_2->square[sq]) return FALSE; - } - - if (board_1->turn != board_2->turn) return FALSE; - if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return FALSE; - if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return FALSE; - if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return FALSE; - if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return FALSE; - if (board_1->ep_square != board_2->ep_square) return FALSE; - - return TRUE; -} - -// board_init_list() - -void board_init_list(board_t * board) { - - int sq_64, sq, piece; - int colour, pos; - - ASSERT(board!=NULL); - - // init - - for (sq_64 = 0; sq_64 < 64; sq_64++) { - sq = square_from_64(sq_64); - board->pos[sq] = -1; - } - - for (piece = 0; piece < 12; piece++) board->number[piece] = 0; - - // white piece list - - colour = White; - pos = 0; - - for (sq_64 = 0; sq_64 < 64; sq_64++) { - sq = square_from_64(sq_64); - piece = board->square[sq]; - ASSERT(pos>=0&&pos<=16); - if (colour_equal(piece,colour) && piece_is_king(piece)) { - board->pos[sq] = pos; - board->list[colour][pos] = sq; - pos++; - board->number[piece_to_12(piece)]++; - } - } - ASSERT(pos==1); - - for (sq_64 = 0; sq_64 < 64; sq_64++) { - sq = square_from_64(sq_64); - piece = board->square[sq]; - ASSERT(pos>=0&&pos<=16); - if (colour_equal(piece,colour) && !piece_is_king(piece)) { - board->pos[sq] = pos; - board->list[colour][pos] = sq; - pos++; - board->number[piece_to_12(piece)]++; - } - } - - ASSERT(pos>=1&&pos<=16); - board->list[colour][pos] = SquareNone; - board->list_size[colour] = pos; - - // black piece list - - colour = Black; - pos = 0; - - for (sq_64 = 0; sq_64 < 64; sq_64++) { - sq = square_from_64(sq_64); - piece = board->square[sq]; - ASSERT(pos>=0&&pos<=16); - if (colour_equal(piece,colour) && piece_is_king(piece)) { - board->pos[sq] = pos; - board->list[colour][pos] = sq; - pos++; - board->number[piece_to_12(piece)]++; - } - } - ASSERT(pos==1); - - for (sq_64 = 0; sq_64 < 64; sq_64++) { - sq = square_from_64(sq_64); - piece = board->square[sq]; - ASSERT(pos>=1&&pos<=16); - if (colour_equal(piece,colour) && !piece_is_king(piece)) { - board->pos[sq] = pos; - board->list[colour][pos] = sq; - pos++; - board->number[piece_to_12(piece)]++; - } - } - - ASSERT(pos>=1&&pos<=16); - board->list[colour][pos] = SquareNone; - board->list_size[colour] = pos; - - // hash key - - board->key = hash_key(board); -} - -// board_flags() - -int board_flags(const board_t * board) { - - int flags; - - flags = 0; - - if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0; - if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1; - if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2; - if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3; - - return flags; -} - -// board_can_play() - -bool board_can_play(const board_t * board) { - - list_t list[1]; - int i, move; - - ASSERT(board_is_ok(board)); - - gen_moves(list,board); - - for (i = 0; i < list_size(list); i++) { - move = list_move(list,i); - if (pseudo_is_legal(move,board)) return TRUE; - } - - return FALSE; // no legal move -} - -// board_mobility() - -int board_mobility(const board_t * board) { - - list_t list[1]; - - ASSERT(board_is_ok(board)); - - gen_legal_moves(list,board); - - return list_size(list); -} - -// board_is_check() - -bool board_is_check(const board_t * board) { - - ASSERT(board_is_ok(board)); - - return is_in_check(board,board->turn); -} - -// board_is_mate() - -bool board_is_mate(const board_t * board) { - - ASSERT(board_is_ok(board)); - - if (!board_is_check(board)) return FALSE; - if (board_can_play(board)) return FALSE; - - return TRUE; -} - -// board_is_stalemate() - -bool board_is_stalemate(const board_t * board) { - - ASSERT(board_is_ok(board)); - - if (board_is_check(board)) return FALSE; - if (board_can_play(board)) return FALSE; - - return TRUE; -} - -// king_pos() - -int king_pos(const board_t * board, int colour) { - - ASSERT(board_is_ok(board)); - ASSERT(colour_is_ok(colour)); - - return board->list[colour][0]; -} - -// board_disp() - -void board_disp(const board_t * board) { - - int file, rank, sq; - int piece, c; - char fen[256]; - char row[9]; - char line[256]; - - ASSERT(board!=NULL); - - if (!board_to_fen(board,fen,256)) ASSERT(FALSE); - my_log("POLYGLOT FEN %s\n",fen); - my_log("POLYGLOT *** CURRENT BOARD ***\n"); - - for (rank = 7; rank >= 0; rank--) { - - for (file = 0; file < 8; file++) { - - sq = square_make(file,rank); - piece = board->square[sq]; - - c = (piece != Empty) ? piece_to_char(piece) : '-'; - row[file]=c; - } - row[8]='\0'; - snprintf(line,sizeof(line),"POLYGLOT %s\n",row); - line[sizeof(line)-1]='\0'; - my_log(line); - } - - my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white"); - my_log("POLYGLOT\n"); -} - -// end of board.cpp - + +// board.c + +// includes + +#include + +#include "attack.h" +#include "board.h" +#include "colour.h" +#include "fen.h" +#include "hash.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "util.h" + +// constants + +static const bool UseSlowDebug = FALSE; + +// functions + +// board_is_ok() + +bool board_is_ok(const board_t * board) { + + int sq, piece; + int colour, pos; + int king, rook; + + if (board == NULL) return FALSE; + + // optional heavy DEBUG mode + + if (!UseSlowDebug) return TRUE; + + // squares + + for (sq = 0; sq < SquareNb; sq++) { + piece = board->square[sq]; + if (square_is_ok(sq)) { + pos = board->pos[sq]; + if (piece == Empty) { + if (pos != -1) return FALSE; + } else { + if (pos < 0) return FALSE; + if (board->list[piece_colour(piece)][pos] != sq) return FALSE; + } + } else { + if (piece != Knight64) return FALSE; + } + } + + // white piece list + + colour = White; + pos = 0; + + if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE; + + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + piece = board->square[sq]; + if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE; + + for (pos++; pos < board->list_size[colour]; pos++) { + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + if (!colour_equal(board->square[sq],colour)) return FALSE; + } + + sq = board->list[colour][pos]; + if (sq != SquareNone) return FALSE; + + // black piece list + + colour = Black; + pos = 0; + + if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE; + + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + piece = board->square[sq]; + if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE; + + for (pos++; pos < board->list_size[colour]; pos++) { + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + if (!colour_equal(board->square[sq],colour)) return FALSE; + } + + sq = board->list[colour][pos]; + if (sq != SquareNone) return FALSE; + + // TODO: material + + if (board->number[WhiteKing12] != 1) return FALSE; + if (board->number[BlackKing12] != 1) return FALSE; + + if (!colour_is_ok(board->turn)) return FALSE; + + // castling status + + if (board->castle[White][SideH] != SquareNone) { + + king = board->list[White][0]; + if ((king < A1) || (king > H1)) return FALSE; + if (board->square[king] != WhiteKing256) return FALSE; + + rook = board->castle[White][SideH]; + if ((rook < A1) || (rook > H1)) return FALSE; + if (board->square[rook] != WhiteRook256) return FALSE; + + if (rook <= king) return FALSE; + } + + if (board->castle[White][SideA] != SquareNone) { + + king = board->list[White][0]; + if ((king < A1) || (king > H1)) return FALSE; + if (board->square[king] != WhiteKing256) return FALSE; + + rook = board->castle[White][SideA]; + if ((rook < A1) || (rook > H1)) return FALSE; + if (board->square[rook] != WhiteRook256) return FALSE; + + if (rook >= king) return FALSE; + } + + if (board->castle[Black][SideH] != SquareNone) { + + king = board->list[Black][0]; + if ((king < A8) || (king > H8)) return FALSE; + if (board->square[king] != BlackKing256) return FALSE; + + rook = board->castle[Black][SideH]; + if ((rook < A8) || (rook > H8)) return FALSE; + if (board->square[rook] != BlackRook256) return FALSE; + + if (rook <= king) return FALSE; + } + + if (board->castle[Black][SideA] != SquareNone) { + + king = board->list[Black][0]; + if (king < A8 || king > H8) return FALSE; + if (board->square[king] != BlackKing256) return FALSE; + + rook = board->castle[Black][SideA]; + if (rook < A8 || rook > H8) return FALSE; + if (board->square[rook] != BlackRook256) return FALSE; + + if (rook >= king) return FALSE; + } + + return TRUE; +} + +// board_clear() + +void board_clear(board_t * board) { + + int file, rank, sq; + int colour, pos; + int piece; + + ASSERT(board!=NULL); + + // edge squares + + for (sq = 0; sq < SquareNb; sq++) { + board->square[sq] = Knight64; // HACK: uncoloured knight + board->pos[sq] = -1; + } + + // empty squares + + for (rank = 0; rank < 8; rank++) { + for (file = 0; file < 8; file++) { + sq = square_make(file,rank); + board->square[sq] = Empty; + } + } + + // piece lists + + for (colour = 0; colour < 3; colour++) { + for (pos = 0; pos < 32; pos++) { // HACK + board->list[colour][pos] = SquareNone; + } + board->list_size[colour] = 0; + } + + // material + + for (piece = 0; piece < 12; piece++) { + board->number[piece] = 0; + } + + // rest + + board->turn = ColourNone; + board->castle[White][SideH] = SquareNone; + board->castle[White][SideA] = SquareNone; + board->castle[Black][SideH] = SquareNone; + board->castle[Black][SideA] = SquareNone; + board->ep_square = SquareNone; + + board->ply_nb = 0; + board->move_nb = 0; + + board->key = 0; +} + +// board_start() + +void board_start(board_t * board) { + + ASSERT(board!=NULL); + + if (!board_from_fen(board,StartFen)) ASSERT(FALSE); +} + +// board_copy() + +void board_copy(board_t * dst, const board_t * src) { + + ASSERT(dst!=NULL); + ASSERT(board_is_ok(src)); + + *dst = *src; +} + +// board_equal() + +bool board_equal(const board_t * board_1, const board_t * board_2) { + + int sq_64, sq; + + ASSERT(board_is_ok(board_1)); + ASSERT(board_is_ok(board_2)); + + // fast comparison + + if (board_1->key != board_2->key) return FALSE; + + // slow comparison + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + if (board_1->square[sq] != board_2->square[sq]) return FALSE; + } + + if (board_1->turn != board_2->turn) return FALSE; + if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return FALSE; + if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return FALSE; + if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return FALSE; + if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return FALSE; + if (board_1->ep_square != board_2->ep_square) return FALSE; + + return TRUE; +} + +// board_init_list() + +void board_init_list(board_t * board) { + + int sq_64, sq, piece; + int colour, pos; + + ASSERT(board!=NULL); + + // init + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + board->pos[sq] = -1; + } + + for (piece = 0; piece < 12; piece++) board->number[piece] = 0; + + // white piece list + + colour = White; + pos = 0; + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=0&&pos<=16); + if (colour_equal(piece,colour) && piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + ASSERT(pos==1); + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=0&&pos<=16); + if (colour_equal(piece,colour) && !piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + + ASSERT(pos>=1&&pos<=16); + board->list[colour][pos] = SquareNone; + board->list_size[colour] = pos; + + // black piece list + + colour = Black; + pos = 0; + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=0&&pos<=16); + if (colour_equal(piece,colour) && piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + ASSERT(pos==1); + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=1&&pos<=16); + if (colour_equal(piece,colour) && !piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + + ASSERT(pos>=1&&pos<=16); + board->list[colour][pos] = SquareNone; + board->list_size[colour] = pos; + + // hash key + + board->key = hash_key(board); +} + +// board_flags() + +int board_flags(const board_t * board) { + + int flags; + + flags = 0; + + if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0; + if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1; + if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2; + if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3; + + return flags; +} + +// board_can_play() + +bool board_can_play(const board_t * board) { + + list_t list[1]; + int i, move; + + ASSERT(board_is_ok(board)); + + gen_moves(list,board); + + for (i = 0; i < list_size(list); i++) { + move = list_move(list,i); + if (pseudo_is_legal(move,board)) return TRUE; + } + + return FALSE; // no legal move +} + +// board_mobility() + +int board_mobility(const board_t * board) { + + list_t list[1]; + + ASSERT(board_is_ok(board)); + + gen_legal_moves(list,board); + + return list_size(list); +} + +// board_is_check() + +bool board_is_check(const board_t * board) { + + ASSERT(board_is_ok(board)); + + return is_in_check(board,board->turn); +} + +// board_is_mate() + +bool board_is_mate(const board_t * board) { + + ASSERT(board_is_ok(board)); + + if (!board_is_check(board)) return FALSE; + if (board_can_play(board)) return FALSE; + + return TRUE; +} + +// board_is_stalemate() + +bool board_is_stalemate(const board_t * board) { + + ASSERT(board_is_ok(board)); + + if (board_is_check(board)) return FALSE; + if (board_can_play(board)) return FALSE; + + return TRUE; +} + +// king_pos() + +int king_pos(const board_t * board, int colour) { + + ASSERT(board_is_ok(board)); + ASSERT(colour_is_ok(colour)); + + return board->list[colour][0]; +} + +// board_disp() + +void board_disp(const board_t * board) { + + int file, rank, sq; + int piece, c; + char fen[256]; + char row[9]; + char line[256]; + + ASSERT(board!=NULL); + + if (!board_to_fen(board,fen,256)) ASSERT(FALSE); + my_log("POLYGLOT FEN %s\n",fen); + my_log("POLYGLOT *** CURRENT BOARD ***\n"); + + for (rank = 7; rank >= 0; rank--) { + + for (file = 0; file < 8; file++) { + + sq = square_make(file,rank); + piece = board->square[sq]; + + c = (piece != Empty) ? piece_to_char(piece) : '-'; + row[file]=c; + } + row[8]='\0'; + snprintf(line,sizeof(line),"POLYGLOT %s\n",row); + line[sizeof(line)-1]='\0'; + my_log(line); + } + + my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white"); + my_log("POLYGLOT\n"); +} + +// end of board.cpp + diff --git a/board.h b/board.h index 4223e83..00ec1c4 100644 --- a/board.h +++ b/board.h @@ -1,70 +1,70 @@ - -// board.h - -#ifndef BOARD_H -#define BOARD_H - -// includes - -#include "colour.h" -#include "square.h" -#include "util.h" - -// defines - -#define Empty 0 -#define SideH 0 -#define SideA 1 -#define SideNb 2 - -// types - -typedef struct { - - uint8 square[SquareNb]; - sint8 pos[SquareNb]; - - uint8 list[ColourNb][32]; - sint8 list_size[ColourNb]; - - sint8 number[12]; - - sint8 turn; - uint8 castle[ColourNb][SideNb]; - uint8 ep_square; - - sint16 ply_nb; - sint16 move_nb; - - uint64 key; -} board_t; - -// functions - -extern bool board_is_ok (const board_t * board); - -extern void board_clear (board_t * board); -extern void board_start (board_t * board); - -extern void board_copy (board_t * dst, const board_t * src); -extern bool board_equal (const board_t * board_1, const board_t * board_2); - -extern void board_init_list (board_t * board); - -extern int board_flags (const board_t * board); - -extern bool board_can_play (const board_t * board); -extern int board_mobility (const board_t * board); - -extern bool board_is_check (const board_t * board); -extern bool board_is_mate (const board_t * board); -extern bool board_is_stalemate (const board_t * board); - -extern int king_pos (const board_t * board, int colour); - -extern void board_disp (const board_t * board); - -#endif // !defined BOARD_H - -// end of board.h - + +// board.h + +#ifndef BOARD_H +#define BOARD_H + +// includes + +#include "colour.h" +#include "square.h" +#include "util.h" + +// defines + +#define Empty 0 +#define SideH 0 +#define SideA 1 +#define SideNb 2 + +// types + +typedef struct { + + uint8 square[SquareNb]; + sint8 pos[SquareNb]; + + uint8 list[ColourNb][32]; + sint8 list_size[ColourNb]; + + sint8 number[12]; + + sint8 turn; + uint8 castle[ColourNb][SideNb]; + uint8 ep_square; + + sint16 ply_nb; + sint16 move_nb; + + uint64 key; +} board_t; + +// functions + +extern bool board_is_ok (const board_t * board); + +extern void board_clear (board_t * board); +extern void board_start (board_t * board); + +extern void board_copy (board_t * dst, const board_t * src); +extern bool board_equal (const board_t * board_1, const board_t * board_2); + +extern void board_init_list (board_t * board); + +extern int board_flags (const board_t * board); + +extern bool board_can_play (const board_t * board); +extern int board_mobility (const board_t * board); + +extern bool board_is_check (const board_t * board); +extern bool board_is_mate (const board_t * board); +extern bool board_is_stalemate (const board_t * board); + +extern int king_pos (const board_t * board, int colour); + +extern void board_disp (const board_t * board); + +#endif // !defined BOARD_H + +// end of board.h + diff --git a/book.c b/book.c index c81df43..49c0962 100644 --- a/book.c +++ b/book.c @@ -1,422 +1,422 @@ - -// book.c - -// includes - -#include -#include -#include -#include - -#include "board.h" -#include "book.h" -#include "move.h" -#include "move_legal.h" -#include "san.h" -#include "util.h" -#include "option.h" - -// types - -typedef struct { - uint64 key; - uint16 move; - uint16 count; - uint16 n; - uint16 sum; -} entry_t; - -// variables - -static FILE * BookFile; -static int BookSize; - -// prototypes - -static int find_pos (uint64 key); - -static void read_entry (entry_t * entry, int n); -static void write_entry (const entry_t * entry, int n); - -static uint64 read_integer (FILE * file, int size); -static void write_integer (FILE * file, int size, uint64 n); - -// functions - -// book_clear() - -void book_clear() { - - BookFile = NULL; - BookSize = 0; -} - -bool book_is_open(){ - return BookFile!=NULL; -} - -// book_open() - -void book_open(const char file_name[]) { - - ASSERT(file_name!=NULL); - if(option_get_bool(Option,"BookLearn")){ - BookFile = fopen(file_name,"rb+"); - }else{ - BookFile = fopen(file_name,"rb"); - } - -// if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); - if (BookFile == NULL) return; - - if (fseek(BookFile,0,SEEK_END) == -1) { - my_fatal("book_open(): fseek(): %s\n",strerror(errno)); - } - - BookSize = ftell(BookFile) / 16; -// if (BookSize == 0) my_fatal("book_open(): empty file\n"); - if (BookSize == 0) { - book_close(); - book_clear(); - }; -} - -// book_close() - -void book_close() { - - if(BookFile==NULL) return; - - if (fclose(BookFile) == EOF) { - my_fatal("book_close(): fclose(): %s\n",strerror(errno)); - } -} - -// is_in_book() - -bool is_in_book(const board_t * board) { - - int pos; - entry_t entry[1]; - - if(BookFile==NULL) return FALSE; - - ASSERT(board!=NULL); - - for (pos = find_pos(board->key); pos < BookSize; pos++) { - read_entry(entry,pos); - if (entry->key == board->key) return TRUE; - } - - return FALSE; -} - -// book_move() - -int book_move(const board_t * board, bool random) { - - int best_move; - int best_score; - int pos; - entry_t entry[1]; - int move; - int score; - list_t list[1]; - int i; - - if(BookFile==NULL) return MoveNone; - - ASSERT(board!=NULL); - ASSERT(random==TRUE||random==FALSE); - - // init - - list_clear(list); - - book_moves(list,board); - - best_move = MoveNone; - best_score = 0; - for(i=0; imove[i]; - score = list->value[i]; - - if (move != MoveNone && - move_is_legal(move,board) && - score>10*option_get_int(Option,"BookTreshold")) { - - // pick this move? - - ASSERT(score>0); - - if (random) { - best_score += score; - if (my_random_int(best_score) < score) best_move = move; - } else { - if (score > best_score) { - best_move = move; - best_score = score; - } - } - - } else { - - ASSERT(FALSE); - } - } - - return best_move; -} - -// book_moves() - -void book_moves(list_t * list, const board_t * board) { - - int first_pos; - int sum; - int pos; - entry_t entry[1]; - int move; - int score; - char move_string[256]; - - ASSERT(board!=NULL); - ASSERT(list!=NULL); - - if(BookFile==NULL) return; - - // init - - list_clear(list); - - first_pos = find_pos(board->key); - - // sum - - sum = 0; - - for (pos = first_pos; pos < BookSize; pos++) { - - read_entry(entry,pos); - if (entry->key != board->key) break; - - sum += entry->count; - } - - // disp - - for (pos = first_pos; pos < BookSize; pos++) { - - read_entry(entry,pos); - if (entry->key != board->key) break; - - move = entry->move; - score = (((uint32)entry->count)*((uint32)10000))/sum; // 32 bit safe! - - if (move != MoveNone && move_is_legal(move,board)) { - list_add_ex(list,move,score); - } - } - -} - - -// book_disp() - -void book_disp(const board_t * board) { - - char move_string[256]; - list_t list[1]; - int i; - int treshold=option_get_int(Option,"BookTreshold"); - - ASSERT(board!=NULL); - - if(BookFile==NULL) return; - - book_moves(list,board); - - for(i=0; imove[i],board,move_string,256); - if(list->value[i]>10*treshold){ - printf(" %6s %5.2f%%\n",move_string,list->value[i]/100.0); - }else{ - printf(" %6s %5.2f%% (below treshold %4.2f%%)\n", - move_string,list->value[i]/100.0,treshold/10.0); - } - } - // this is necessary by the xboard protocol - printf("\n"); -} - -// book_learn_move() - -void book_learn_move(const board_t * board, int move, int result) { - - int pos; - entry_t entry[1]; - - if(BookFile==NULL) return; - - ASSERT(board!=NULL); - ASSERT(move_is_ok(move)); - ASSERT(result>=-1&&result<=+1); - - ASSERT(move_is_legal(move,board)); - - for (pos = find_pos(board->key); pos < BookSize; pos++) { - - read_entry(entry,pos); - if (entry->key != board->key) break; - - if (entry->move == move) { - - entry->n++; - entry->sum += result+1; - - write_entry(entry,pos); - - break; - } - } -} - -// book_flush() - -void book_flush() { - - if(BookFile==NULL) return; - - if (fflush(BookFile) == EOF) { - my_fatal("book_flush(): fflush(): %s\n",strerror(errno)); - } -} - -// find_pos() - -static int find_pos(uint64 key) { - - int left, right, mid; - entry_t entry[1]; - - // binary search (finds the leftmost entry) - - left = 0; - right = BookSize-1; - - ASSERT(left<=right); - - while (left < right) { - - mid = (left + right) / 2; - ASSERT(mid>=left&&midkey) { - right = mid; - } else { - left = mid+1; - } - } - - ASSERT(left==right); - - read_entry(entry,left); - - return (entry->key == key) ? left : BookSize; -} - -// read_entry() - -static void read_entry(entry_t * entry, int n) { - - ASSERT(entry!=NULL); - ASSERT(n>=0&&nkey = read_integer(BookFile,8); - entry->move = read_integer(BookFile,2); - entry->count = read_integer(BookFile,2); - entry->n = read_integer(BookFile,2); - entry->sum = read_integer(BookFile,2); -} - -// write_entry() - -static void write_entry(const entry_t * entry, int n) { - - ASSERT(entry!=NULL); - ASSERT(n>=0&&nkey); - write_integer(BookFile,2,entry->move); - write_integer(BookFile,2,entry->count); - write_integer(BookFile,2,entry->n); - write_integer(BookFile,2,entry->sum); -} - -// read_integer() - -static uint64 read_integer(FILE * file, int size) { - - uint64 n; - int i; - int b; - - ASSERT(file!=NULL); - ASSERT(size>0&&size<=8); - - n = 0; - - for (i = 0; i < size; i++) { - - b = fgetc(file); - - if (b == EOF) { - if (feof(file)) { - my_fatal("read_integer(): fgetc(): EOF reached\n"); - } else { // error - my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); - } - } - - ASSERT(b>=0&&b<256); - n = (n << 8) | b; - } - - return n; -} - -// write_integer() - -static void write_integer(FILE * file, int size, uint64 n) { - - int i; - int b; - - ASSERT(file!=NULL); - ASSERT(size>0&&size<=8); - ASSERT(size==8||n>>(size*8)==0); - - for (i = size-1; i >= 0; i--) { - - b = (n >> (i*8)) & 0xFF; - ASSERT(b>=0&&b<256); - - if (fputc(b,file) == EOF) { - my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); - } - } -} - -// end of book.cpp - + +// book.c + +// includes + +#include +#include +#include +#include + +#include "board.h" +#include "book.h" +#include "move.h" +#include "move_legal.h" +#include "san.h" +#include "util.h" +#include "option.h" + +// types + +typedef struct { + uint64 key; + uint16 move; + uint16 count; + uint16 n; + uint16 sum; +} entry_t; + +// variables + +static FILE * BookFile; +static int BookSize; + +// prototypes + +static int find_pos (uint64 key); + +static void read_entry (entry_t * entry, int n); +static void write_entry (const entry_t * entry, int n); + +static uint64 read_integer (FILE * file, int size); +static void write_integer (FILE * file, int size, uint64 n); + +// functions + +// book_clear() + +void book_clear() { + + BookFile = NULL; + BookSize = 0; +} + +bool book_is_open(){ + return BookFile!=NULL; +} + +// book_open() + +void book_open(const char file_name[]) { + + ASSERT(file_name!=NULL); + if(option_get_bool(Option,"BookLearn")){ + BookFile = fopen(file_name,"rb+"); + }else{ + BookFile = fopen(file_name,"rb"); + } + +// if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + if (BookFile == NULL) return; + + if (fseek(BookFile,0,SEEK_END) == -1) { + my_fatal("book_open(): fseek(): %s\n",strerror(errno)); + } + + BookSize = ftell(BookFile) / 16; +// if (BookSize == 0) my_fatal("book_open(): empty file\n"); + if (BookSize == 0) { + book_close(); + book_clear(); + }; +} + +// book_close() + +void book_close() { + + if(BookFile==NULL) return; + + if (fclose(BookFile) == EOF) { + my_fatal("book_close(): fclose(): %s\n",strerror(errno)); + } +} + +// is_in_book() + +bool is_in_book(const board_t * board) { + + int pos; + entry_t entry[1]; + + if(BookFile==NULL) return FALSE; + + ASSERT(board!=NULL); + + for (pos = find_pos(board->key); pos < BookSize; pos++) { + read_entry(entry,pos); + if (entry->key == board->key) return TRUE; + } + + return FALSE; +} + +// book_move() + +int book_move(const board_t * board, bool random) { + + int best_move; + int best_score; + int pos; + entry_t entry[1]; + int move; + int score; + list_t list[1]; + int i; + + if(BookFile==NULL) return MoveNone; + + ASSERT(board!=NULL); + ASSERT(random==TRUE||random==FALSE); + + // init + + list_clear(list); + + book_moves(list,board); + + best_move = MoveNone; + best_score = 0; + for(i=0; imove[i]; + score = list->value[i]; + + if (move != MoveNone && + move_is_legal(move,board) && + score>10*option_get_int(Option,"BookTreshold")) { + + // pick this move? + + ASSERT(score>0); + + if (random) { + best_score += score; + if (my_random_int(best_score) < score) best_move = move; + } else { + if (score > best_score) { + best_move = move; + best_score = score; + } + } + + } else { + + ASSERT(FALSE); + } + } + + return best_move; +} + +// book_moves() + +void book_moves(list_t * list, const board_t * board) { + + int first_pos; + int sum; + int pos; + entry_t entry[1]; + int move; + int score; + char move_string[256]; + + ASSERT(board!=NULL); + ASSERT(list!=NULL); + + if(BookFile==NULL) return; + + // init + + list_clear(list); + + first_pos = find_pos(board->key); + + // sum + + sum = 0; + + for (pos = first_pos; pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + sum += entry->count; + } + + // disp + + for (pos = first_pos; pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + move = entry->move; + score = (((uint32)entry->count)*((uint32)10000))/sum; // 32 bit safe! + + if (move != MoveNone && move_is_legal(move,board)) { + list_add_ex(list,move,score); + } + } + +} + + +// book_disp() + +void book_disp(const board_t * board) { + + char move_string[256]; + list_t list[1]; + int i; + int treshold=option_get_int(Option,"BookTreshold"); + + ASSERT(board!=NULL); + + if(BookFile==NULL) return; + + book_moves(list,board); + + for(i=0; imove[i],board,move_string,256); + if(list->value[i]>10*treshold){ + printf(" %6s %5.2f%%\n",move_string,list->value[i]/100.0); + }else{ + printf(" %6s %5.2f%% (below treshold %4.2f%%)\n", + move_string,list->value[i]/100.0,treshold/10.0); + } + } + // this is necessary by the xboard protocol + printf("\n"); +} + +// book_learn_move() + +void book_learn_move(const board_t * board, int move, int result) { + + int pos; + entry_t entry[1]; + + if(BookFile==NULL) return; + + ASSERT(board!=NULL); + ASSERT(move_is_ok(move)); + ASSERT(result>=-1&&result<=+1); + + ASSERT(move_is_legal(move,board)); + + for (pos = find_pos(board->key); pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + if (entry->move == move) { + + entry->n++; + entry->sum += result+1; + + write_entry(entry,pos); + + break; + } + } +} + +// book_flush() + +void book_flush() { + + if(BookFile==NULL) return; + + if (fflush(BookFile) == EOF) { + my_fatal("book_flush(): fflush(): %s\n",strerror(errno)); + } +} + +// find_pos() + +static int find_pos(uint64 key) { + + int left, right, mid; + entry_t entry[1]; + + // binary search (finds the leftmost entry) + + left = 0; + right = BookSize-1; + + ASSERT(left<=right); + + while (left < right) { + + mid = (left + right) / 2; + ASSERT(mid>=left&&midkey) { + right = mid; + } else { + left = mid+1; + } + } + + ASSERT(left==right); + + read_entry(entry,left); + + return (entry->key == key) ? left : BookSize; +} + +// read_entry() + +static void read_entry(entry_t * entry, int n) { + + ASSERT(entry!=NULL); + ASSERT(n>=0&&nkey = read_integer(BookFile,8); + entry->move = read_integer(BookFile,2); + entry->count = read_integer(BookFile,2); + entry->n = read_integer(BookFile,2); + entry->sum = read_integer(BookFile,2); +} + +// write_entry() + +static void write_entry(const entry_t * entry, int n) { + + ASSERT(entry!=NULL); + ASSERT(n>=0&&nkey); + write_integer(BookFile,2,entry->move); + write_integer(BookFile,2,entry->count); + write_integer(BookFile,2,entry->n); + write_integer(BookFile,2,entry->sum); +} + +// read_integer() + +static uint64 read_integer(FILE * file, int size) { + + uint64 n; + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + + n = 0; + + for (i = 0; i < size; i++) { + + b = fgetc(file); + + if (b == EOF) { + if (feof(file)) { + my_fatal("read_integer(): fgetc(): EOF reached\n"); + } else { // error + my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); + } + } + + ASSERT(b>=0&&b<256); + n = (n << 8) | b; + } + + return n; +} + +// write_integer() + +static void write_integer(FILE * file, int size, uint64 n) { + + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + ASSERT(size==8||n>>(size*8)==0); + + for (i = size-1; i >= 0; i--) { + + b = (n >> (i*8)) & 0xFF; + ASSERT(b>=0&&b<256); + + if (fputc(b,file) == EOF) { + my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); + } + } +} + +// end of book.cpp + diff --git a/book.h b/book.h index 9f3440a..73bd808 100644 --- a/book.h +++ b/book.h @@ -1,32 +1,32 @@ - -// book.h - -#ifndef BOOK_H -#define BOOK_H - -// includes - -#include "board.h" -#include "util.h" -#include "list.h" - -// functions - -extern void book_clear (); - -extern void book_open (const char file_name[]); -extern bool book_is_open (); -extern void book_close (); - -extern bool is_in_book (const board_t * board); -extern int book_move (const board_t * board, bool random); -extern void book_moves (list_t * list, const board_t * board); -extern void book_disp (const board_t * board); - -extern void book_learn_move (const board_t * board, int move, int result); -extern void book_flush (); - -#endif // !defined BOOK_H - -// end of book.h - + +// book.h + +#ifndef BOOK_H +#define BOOK_H + +// includes + +#include "board.h" +#include "util.h" +#include "list.h" + +// functions + +extern void book_clear (); + +extern void book_open (const char file_name[]); +extern bool book_is_open (); +extern void book_close (); + +extern bool is_in_book (const board_t * board); +extern int book_move (const board_t * board, bool random); +extern void book_moves (list_t * list, const board_t * board); +extern void book_disp (const board_t * board); + +extern void book_learn_move (const board_t * board, int move, int result); +extern void book_flush (); + +#endif // !defined BOOK_H + +// end of book.h + diff --git a/book_make.c b/book_make.c index c3d5a28..c9500a2 100644 --- a/book_make.c +++ b/book_make.c @@ -1,1084 +1,1083 @@ -// book_make.c - -// includes - -#include -#include -#include -#include -#include - -#include "board.h" -#include "book_make.h" -#include "move.h" -#include "move_do.h" -#include "move_gen.h" -#include "move_legal.h" -#include "pgn.h" -#include "san.h" -#include "util.h" - -// constants - -#define COUNT_MAX ((int)16384) -#define StringSize ((int)4096) - -static const int NIL = -1; - -// defines - -#define opp_search(s) ((s)==BOOK?ALL:BOOK) - -// types - -typedef struct { - uint64 key; - uint16 move; - uint16 count; -// Unfortunately the minggw32 cross compiler [4.2.1-sjlj (mingw32-2)] -// seems to have a bug with anon structs contained in unions when using -O2. -// See the ASSERT below in "read_entry_file"... -// To be fair this seems to be illegal in C++ -// although it is hard to understand why, and the compiler does not complain -// even with -Wall. -// union { -// struct { - uint16 n; - uint16 sum; -// }; -// struct { - uint8 height; - int line; -// }; -// }; - uint8 colour; -} entry_t; - -typedef struct { - int size; - int alloc; - uint32 mask; - entry_t * entry; - sint32 * hash; -} book_t; - -typedef enum { - BOOK, - ALL -} search_t; - -typedef struct { - int height; - int line; - int initial_color; - bool book_trans_only; - bool extended_search; - uint16 moves[1024]; - double probs[1024]; - uint64 keys[1024]; - FILE *output; -} info_t; - - -// variables - -static int MaxPly; -static int MinGame; -static double MinScore; -static bool RemoveWhite, RemoveBlack; -static bool Uniform; -static bool Quiet=FALSE; - -static book_t Book[1]; - -// prototypes - -static void book_clear (); -static void book_insert (const char file_name[]); -static void book_filter (); -static void book_sort (); -static void book_save (const char file_name[]); - -static int find_entry (const board_t * board, int move); -static void resize (); -static void halve_stats (uint64 key); - -static bool keep_entry (int pos); - -static int entry_score (const entry_t * entry); - -static int key_compare (const void * p1, const void * p2); - -static void write_integer (FILE * file, int size, uint64 n); -static uint64 read_integer(FILE * file, int size); - -static void read_entry_file(FILE *f, entry_t *entry); -static void write_entry_file(FILE * f, const entry_t * entry); - -// functions - -// book_make() - -void book_make(int argc, char * argv[]) { - - int i; - const char * pgn_file; - const char * bin_file; - - pgn_file = NULL; - my_string_set(&pgn_file,"book.pgn"); - - bin_file = NULL; - my_string_set(&bin_file,"book.bin"); - - MaxPly = 1024; - MinGame = 3; - MinScore = 0.0; - RemoveWhite = FALSE; - RemoveBlack = FALSE; - Uniform = FALSE; - - for (i = 1; i < argc; i++) { - - if (FALSE) { - - } else if (my_string_equal(argv[i],"make-book")) { - - // skip - - } else if (my_string_equal(argv[i],"-pgn")) { - - i++; - if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); - - my_string_set(&pgn_file,argv[i]); - - } else if (my_string_equal(argv[i],"-bin")) { - - i++; - if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); - - my_string_set(&bin_file,argv[i]); - - } else if (my_string_equal(argv[i],"-max-ply")) { - - i++; - if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); - - MaxPly = atoi(argv[i]); - ASSERT(MaxPly>=0); - - } else if (my_string_equal(argv[i],"-min-game")) { - - i++; - if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); - - MinGame = atoi(argv[i]); - ASSERT(MinGame>0); - - } else if (my_string_equal(argv[i],"-min-score")) { - - i++; - if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); - - MinScore = atof(argv[i]) / 100.0; - ASSERT(MinScore>=0.0&&MinScore<=1.0); - - } else if (my_string_equal(argv[i],"-only-white")) { - - RemoveWhite = FALSE; - RemoveBlack = TRUE; - - } else if (my_string_equal(argv[i],"-only-black")) { - - RemoveWhite = TRUE; - RemoveBlack = FALSE; - - } else if (my_string_equal(argv[i],"-uniform")) { - - Uniform = TRUE; - - } else { - - my_fatal("book_make(): unknown option \"%s\"\n",argv[i]); - } - } - - book_clear(); - - printf("inserting games ...\n"); - book_insert(pgn_file); - - printf("filtering entries ...\n"); - book_filter(); - - printf("sorting entries ...\n"); - book_sort(); - - printf("saving entries ...\n"); - book_save(bin_file); - - printf("all done!\n"); -} - -// book_clear() - -static void book_clear() { - - int index; - - Book->alloc = 1; - Book->mask = (Book->alloc * 2) - 1; - - Book->entry = (entry_t *) my_malloc(Book->alloc*sizeof(entry_t)); - Book->size = 0; - - Book->hash = (sint32 *) my_malloc((Book->alloc*2)*sizeof(sint32)); - for (index = 0; index < Book->alloc*2; index++) { - Book->hash[index] = NIL; - } -} - -// book_insert() - -static void book_insert(const char file_name[]) { - - pgn_t pgn[1]; - board_t board[1]; - int ply; - int result; - char string[256]; - int move; - int pos; - - ASSERT(file_name!=NULL); - - // init - - pgn->game_nb=1; - // scan loop - - pgn_open(pgn,file_name); - - while (pgn_next_game(pgn)) { - - board_start(board); - ply = 0; - result = 0; - - if (FALSE) { - } else if (my_string_equal(pgn->result,"1-0")) { - result = +1; - } else if (my_string_equal(pgn->result,"0-1")) { - result = -1; - } - - while (pgn_next_move(pgn,string,256)) { - - if (ply < MaxPly) { - - move = move_from_san(string,board); - - if (move == MoveNone || !move_is_legal(move,board)) { - my_fatal("book_insert(): illegal move \"%s\" at line %d, column %d,game %d\n",string,pgn->move_line,pgn->move_column,pgn->game_nb); - } - - pos = find_entry(board,move); - - Book->entry[pos].n++; - Book->entry[pos].sum += result+1; - - if (Book->entry[pos].n >= COUNT_MAX) { - halve_stats(board->key); - } - - move_do(board,move); - ply++; - result = -result; - } - } - pgn->game_nb++; - if (pgn->game_nb % 10000 == 0) printf("%d games ...\n",pgn->game_nb); - } - - pgn_close(pgn); - - printf("%d game%s.\n",pgn->game_nb,(pgn->game_nb>2)?"s":""); - printf("%d entries.\n",Book->size); - - return; -} - -// book_filter() - -static void book_filter() { - - int src, dst; - - // entry loop - - dst = 0; - - for (src = 0; src < Book->size; src++) { - if (keep_entry(src)) Book->entry[dst++] = Book->entry[src]; - } - - ASSERT(dst>=0&&dst<=Book->size); - Book->size = dst; - - printf("%d entries.\n",Book->size); -} - -// book_sort() - -static void book_sort() { - - // sort keys for binary search - - qsort(Book->entry,Book->size,sizeof(entry_t),&key_compare); -} - -// book_save() - -static void book_save(const char file_name[]) { - - FILE * file; - int pos; - - ASSERT(file_name!=NULL); - - file = fopen(file_name,"wb"); - if (file == NULL) my_fatal("book_save(): can't open file \"%s\" for writing: %s\n",file_name,strerror(errno)); - - // entry loop - - for (pos = 0; pos < Book->size; pos++) { - - ASSERT(keep_entry(pos)); - - write_integer(file,8,Book->entry[pos].key); - write_integer(file,2,Book->entry[pos].move); - write_integer(file,2,entry_score(&Book->entry[pos])); - write_integer(file,2,0); - write_integer(file,2,0); - } - - fclose(file); -} - -// find_entry() - -static int find_entry(const board_t * board, int move) { - - uint64 key; - int index; - int pos; - - ASSERT(board!=NULL); - ASSERT(move==MoveNone || move_is_ok(move)); - - ASSERT(move==MoveNone || move_is_legal(move,board)); - - // init - - key = board->key; - - // search - - for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { - - ASSERT(pos>=0&&possize); - - if (Book->entry[pos].key == key && Book->entry[pos].move == move) { - return pos; // found - } - } - - // not found - - ASSERT(Book->size<=Book->alloc); - - if (Book->size == Book->alloc) { - - // allocate more memory - - resize(); - - for (index = key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask) - ; - } - - // create a new entry - - ASSERT(Book->sizealloc); - pos = Book->size++; - - Book->entry[pos].key = key; - Book->entry[pos].move = move; - Book->entry[pos].n = 0; - Book->entry[pos].sum = 0; - Book->entry[pos].colour = board->turn; - - // insert into the hash table - - ASSERT(index>=0&&indexalloc*2); - ASSERT(Book->hash[index]==NIL); - Book->hash[index] = pos; - - ASSERT(pos>=0&&possize); - - return pos; -} - -// rebuild_hash_table - -static void rebuild_hash_table(){ - int index,pos; - for (index = 0; index < Book->alloc*2; index++) { - Book->hash[index] = NIL; - } - for (pos = 0; pos < Book->size; pos++) { - for (index = Book->entry[pos].key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask) - ; - ASSERT(index>=0&&indexalloc*2); - Book->hash[index] = pos; - } -} - -static void resize() { - - int size; - - ASSERT(Book->size==Book->alloc); - - Book->alloc *= 2; - Book->mask = (Book->alloc * 2) - 1; - - size = 0; - size += Book->alloc * sizeof(entry_t); - size += (Book->alloc*2) * sizeof(sint32); - - if (size >= 1048576) if(!Quiet){ - printf("allocating %gMB ...\n",((double)size)/1048576.0); - } - - // resize arrays - - Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t)); - Book->hash = (sint32 *) my_realloc(Book->hash,(Book->alloc*2)*sizeof(sint32)); - - // rebuild hash table - - rebuild_hash_table(); -} - - -// halve_stats() - -static void halve_stats(uint64 key) { - - int index; - int pos; - - // search - - for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { - - ASSERT(pos>=0&&possize); - - if (Book->entry[pos].key == key) { - Book->entry[pos].n = (Book->entry[pos].n + 1) / 2; - Book->entry[pos].sum = (Book->entry[pos].sum + 1) / 2; - } - } -} - -// keep_entry() - -static bool keep_entry(int pos) { - - const entry_t * entry; - int colour; - double score; - - ASSERT(pos>=0&&possize); - - entry = &Book->entry[pos]; - - // if (entry->n == 0) return FALSE; - if (entry->n < MinGame) return FALSE; - - if (entry->sum == 0) return FALSE; - - score = (((double)entry->sum) / ((double)entry->n)) / 2.0; - ASSERT(score>=0.0&&score<=1.0); - - if (score < MinScore) return FALSE; - - colour = entry->colour; - - if ((RemoveWhite && colour_is_white(colour)) - || (RemoveBlack && colour_is_black(colour))) { - return FALSE; - } - - if (entry_score(entry) == 0) return FALSE; // REMOVE ME? - - return TRUE; -} - -// entry_score() - -static int entry_score(const entry_t * entry) { - - int score; - - ASSERT(entry!=NULL); - - // score = entry->n; // popularity - score = entry->sum; // "expectancy" - - if (Uniform) score = 1; - - ASSERT(score>=0); - - return score; -} - -// key_compare() - -static int key_compare(const void * p1, const void * p2) { - - const entry_t * entry_1, * entry_2; - - ASSERT(p1!=NULL); - ASSERT(p2!=NULL); - - entry_1 = (const entry_t *) p1; - entry_2 = (const entry_t *) p2; - - if (entry_1->key > entry_2->key) { - return +1; - } else if (entry_1->key < entry_2->key) { - return -1; - } else { - return entry_score(entry_2) - entry_score(entry_1); // highest score first - } -} - -// write_integer() - -static void write_integer(FILE * file, int size, uint64 n) { - - int i; - int b; - - ASSERT(file!=NULL); - ASSERT(size>0&&size<=8); - ASSERT(size==8||n>>(size*8)==0); - - for (i = size-1; i >= 0; i--) { - b = (n >> (i*8)) & 0xFF; - ASSERT(b>=0&&b<256); - fputc(b,file); - } -} - -// read_integer() - -static uint64 read_integer(FILE * file, int size) { - uint64 n; - int i; - int b; - ASSERT(file!=NULL); - ASSERT(size>0&&size<=8); - n = 0; - for (i = 0; i < size; i++) { - b = fgetc(file); - if (b == EOF) { - if (feof(file)) { - my_fatal("read_integer(): fgetc(): EOF reached\n"); - } else { // error - my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); - } - } - ASSERT(b>=0&&b<256); - n = (n << 8) | b; - } - return n; -} - -// read_entry_file - -static void read_entry_file(FILE *f, entry_t *entry){ - uint64 n; - ASSERT(entry!=NULL); - n = entry->key = read_integer(f,8); - entry->move = read_integer(f,2); - entry->count = read_integer(f,2); - entry->n = read_integer(f,2); - entry->sum = read_integer(f,2); - ASSERT(n==entry->key); // test for mingw compiler bug with anon structs -} - -// write_entry_file - -static void write_entry_file(FILE * f, const entry_t * entry) { - ASSERT(entry!=NULL); - write_integer(f,8,entry->key); - write_integer(f,2,entry->move); - write_integer(f,2,entry->count); - write_integer(f,2,entry->n); - write_integer(f,2,entry->sum); -} - -static void print_list(const board_t *board, list_t *list){ - int i; - uint16 move; - char move_string[256]; - for (i = 0; i < list_size(list); i++) { - move = list_move(list,i); - move_to_san(move,board,move_string,256); - printf("%s",move_string); - } - printf("\n"); -} - -// book_load() -// loads a polyglot book - -static void book_load(const char filename[]){ - FILE* f; - entry_t entry[1]; - int size; - int i; - int pos; - int index; - ASSERT(filename!=NULL); - if(!(f=fopen(filename,"rb"))){ - my_fatal("book_load() : can't open file \"%s\" for reading: %s\n",filename,strerror(errno)); - } - fseek(f,0L,SEEK_END); // superportable way to get size of book! - size=ftell(f)/16; - fseek(f,0,SEEK_SET); - for(i=0L;isize<=Book->alloc); - if (Book->size == Book->alloc) { - // allocate more memoryx - resize(); - } - // insert into the book - pos = Book->size++; - Book->entry[pos].key = entry->key; - ASSERT(entry->move!=MoveNone); - Book->entry[pos].move = entry->move; - Book->entry[pos].count = entry->count; - Book->entry[pos].n = entry->n; - Book->entry[pos].sum = entry->sum; - Book->entry[pos].colour = ColourNone; - // find free hash table spot - for (index = entry->key & (uint64) Book->mask; - Book->hash[index] != NIL; - index = (index+1) & Book->mask); - // insert into the hash table - ASSERT(index>=0&&indexalloc*2); - ASSERT(Book->hash[index]==NIL); - Book->hash[index] = pos; - ASSERT(pos>=0&&possize); - } - fclose(f); -} - -// gen_book_moves() -// similar signature as gen_legal_moves -static int gen_book_moves(list_t * list, const board_t * board){ - int first_pos, pos, index; - entry_t entry[1]; - bool found; - list_clear(list); - found=FALSE; - for (index = board->key & (uint64) Book->mask; (first_pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { - ASSERT(first_pos>=0&&first_possize); - if (Book->entry[first_pos].key == board->key) { - found=TRUE; - break; // found - } - } - if(!found) return -1; - if(Book->entry[first_pos].move==MoveNone) return -1; - for (pos = first_pos; pos < Book->size; pos++) { - *entry=Book->entry[pos]; - if (entry->key != board->key) break; - if (entry->count > 0 && - entry->move != MoveNone && - move_is_legal(entry->move,board)) { - list_add_ex(list,entry->move,entry->count); - } - } - return first_pos; -} - -// gen_opp_book_moves() -// moves to which opponent has a reply in book -// similar signature as gen_legal_moves -static void gen_opp_book_moves(list_t * list, const board_t * board){ - int move; - list_t new_list[1], legal_moves[1]; - board_t new_board[1]; - int i; - list_clear(list); - gen_legal_moves(legal_moves,board); - for (i = 0; i < list_size(legal_moves); i++) { - move = list_move(legal_moves,i); - // scratch_board - memcpy(new_board, board, sizeof(board_t)); - move_do(new_board,move); - gen_book_moves(new_list,new_board); // wasteful in time but tested! - if(list_size(new_list)!=0){ - list_add(list,move); - } - } -} - -static void print_moves(info_t *info){ - board_t board[1]; - char move_string[256]; - int i; - int color=White; - if(!info->output){ - return; - } - board_start(board); - for(i=0;iheight;i++){ - if(color==White){ - fprintf(info->output,"%d. ",i/2+1); - color=Black; - }else{ - color=White; - } - move_to_san(info->moves[i],board,move_string,256); - fprintf(info->output,"%s", move_string); - if(color==colour_opp(info->initial_color)){ - fprintf(info->output,"{%.0f%%} ",100*info->probs[i]); - }else{ - fprintf(info->output," "); - } - move_do(board,info->moves[i]); - } -} - -static int search_book(board_t *board, info_t *info, search_t search){ - list_t list[1]; - board_t new_board[1]; - uint16 move; - int count; - int ret; - int i; - int offset; - int pos; - int size; - int prob_sum; - double probs[256]; - for(i=0;i<256;i++){ - probs[i]=0.0; // kill compiler warnings - } - for(i=0;iheight;i++){ - if(board->key==info->keys[i]){ - if(info->output){ - fprintf(info->output,"%d: ",info->line); - print_moves(info); - fprintf(info->output,"{cycle: ply=%d}\n",i); - } - info->line++; - return 1; // end of line because of cycle - } - } - if(!info->book_trans_only || (info->book_trans_only && search==BOOK)){ - info->keys[info->height]=board->key; - size=Book->size; // hack - pos=find_entry(board,MoveNone); - if(size==Book->size){ - if(info->output){ - fprintf(info->output,"%d: ",info->line); - print_moves(info); - fprintf(info->output,"{trans: line=%d, ply=%d}\n", - Book->entry[pos].line, - Book->entry[pos].height); - } - info->line++; - return 1; // end of line because of transposition - }else{ - Book->entry[pos].height=info->height; - Book->entry[pos].line=info->line; - } - } - count=0; - if(search==BOOK){ - offset=gen_book_moves(list,board); - if(info->extended_search){ - gen_legal_moves(list,board); - } -// ASSERT(offset!=-1); - if(offset!=-1){ // only FALSE in starting position for black book - Book->entry[offset].colour=board->turn; - prob_sum=0; - if(!info->extended_search){ - for(i=0;imoves[info->height++]=move; - if(search==BOOK){ - info->probs[info->height-1]=probs[i]; - } - ret=search_book(new_board, info, opp_search(search)); - if(ret==0 && search==BOOK){ - if(info->output){ - fprintf(info->output,"%d: ",info->line); - print_moves(info); - fprintf(info->output,"\n"); - } - info->line++; - ret=1; // end of line book move counts for 1 - } - info->height--; - ASSERT(info->height>=0); - count+=ret; - } - return count; -} - -void init_info(info_t *info){ - info->line=1; - info->height=0; - info->output=NULL; - info->initial_color=White; - info->book_trans_only=FALSE; -} - -// book_clean() -// remove MoveNone entries from book and rebuild hash table -void book_clean(){ - int read_ptr,write_ptr; - write_ptr=0; - for(read_ptr=0;read_ptrsize;read_ptr++){ - if(Book->entry[read_ptr].move!=MoveNone){ - Book->entry[write_ptr++]=Book->entry[read_ptr]; - } - } - Book->size=write_ptr; - rebuild_hash_table(); -} - -// book_dump() - -void book_dump(int argc, char * argv[]) { - const char * bin_file=NULL; - const char * txt_file=NULL; - char string[StringSize]; - int color=ColourNone; - board_t board[1]; - info_t info[1]; - int i; - FILE *f; - my_string_set(&bin_file,"book.bin"); - for (i = 1; i < argc; i++) { - if (FALSE) { - } else if (my_string_equal(argv[i],"dump-book")) { - // skip - } else if (my_string_equal(argv[i],"-bin")) { - i++; - if (i==argc) my_fatal("book_dump(): missing argument\n"); - my_string_set(&bin_file,argv[i]); - } else if (my_string_equal(argv[i],"-out")) { - i++; - if (i==argc) my_fatal("book_dump(): missing argument\n"); - my_string_set(&txt_file,argv[i]); - } else if (my_string_equal(argv[i],"-color") || my_string_equal(argv[i],"-colour")) { - i++; - if (i == argc) my_fatal("book_dump(): missing argument\n"); - if(my_string_equal(argv[i],"white")){ - color=White; - }else if (my_string_equal(argv[i],"black")){ - color=Black; - }else{ - my_fatal("book_dump(): unknown color \"%s\"\n",argv[i]); - } - } else { - my_fatal("book_dump(): unknown option \"%s\"\n",argv[i]); - } - } - if(color==ColourNone){ - my_fatal("book_dump(): you must specify a color\n"); - } - if(txt_file==NULL){ - snprintf(string,StringSize,"book_%s.txt",color?"white":"black"); - my_string_set(&txt_file,string); - } - - book_clear(); - if(!Quiet){printf("loading book ...\n");} - book_load(bin_file); - board_start(board); - init_info(info); - info->initial_color=color; - if(!(f=fopen(txt_file,"w"))){ - my_fatal("book_dump(): can't open file \"%s\" for writing: %s", - txt_file,strerror(errno)); - } - info->output=f; - fprintf(info->output,"Dump of \"%s\" for %s.\n", - bin_file,color==White?"white":"black"); - if(color==White){ - if(!Quiet){printf("generating lines for white...\n");} - search_book(board,info, BOOK); - }else{ - if(!Quiet){printf("generating lines for black...\n");} - search_book(board,info, ALL); - } -} - -// book_info() - -void book_info(int argc,char* argv[]){ - const char *bin_file=NULL; - board_t board[1]; - info_t info[1]; - uint64 last_key; - int pos; - int white_pos,black_pos,total_pos,white_pos_extended, - black_pos_extended,white_pos_extended_diff,black_pos_extended_diff; - int s; - bool extended_search=FALSE; - int i; - Quiet=TRUE; - my_string_set(&bin_file,"book.bin"); - - for (i = 1; i < argc; i++) { - if (FALSE) { - } else if (my_string_equal(argv[i],"info-book")) { - // skip - } else if (my_string_equal(argv[i],"-bin")) { - i++; - if (i==argc) my_fatal("book_info(): missing argument\n"); - my_string_set(&bin_file,argv[i]); - } else if (my_string_equal(argv[i],"-exact")) { - extended_search=TRUE; - } else { - my_fatal("book_info(): unknown option \"%s\"\n",argv[i]); - } - } - book_clear(); - if(!Quiet){printf("loading book ...\n");} - book_load(bin_file); - s=Book->size; - - board_start(board); - init_info(info); - info->book_trans_only=FALSE; - info->initial_color=White; - info->extended_search=FALSE; - search_book(board,info, BOOK); - printf("Lines for white : %8d\n",info->line-1); - - - info->line=1; - info->height=0; - info->initial_color=Black; - book_clean(); - ASSERT(Book->size==s); - board_start(board); - search_book(board,info, ALL); - printf("Lines for black : %8d\n",info->line-1); - - book_clean(); - ASSERT(Book->size==s); - white_pos=0; - black_pos=0; - total_pos=0; - last_key=0; - for(pos=0;possize;pos++){ - if(Book->entry[pos].key==last_key){ - ASSERT(Book->entry[pos].colour==ColourNone); - continue; - } - last_key=Book->entry[pos].key; - total_pos++; - if(Book->entry[pos].colour==White){ - white_pos++; - }else if(Book->entry[pos].colour==Black){ - black_pos++; - } - } - printf("Positions on lines for white : %8d\n",white_pos); - printf("Positions on lines for black : %8d\n",black_pos); - - - if(extended_search){ - init_info(info); - info->book_trans_only=TRUE; - info->initial_color=White; - info->extended_search=TRUE; - book_clean(); - board_start(board); - search_book(board,info, BOOK); - - init_info(info); - info->book_trans_only=TRUE; - info->initial_color=Black; - info->extended_search=TRUE; - book_clean(); - board_start(board); - search_book(board,info, ALL); - book_clean(); - ASSERT(Book->size==s); - white_pos_extended=0; - black_pos_extended=0; - last_key=0; - for(pos=0;possize;pos++){ - if(Book->entry[pos].key==last_key){ - ASSERT(Book->entry[pos].colour==ColourNone); - continue; - } - last_key=Book->entry[pos].key; - if(Book->entry[pos].colour==White){ - white_pos_extended++; - }else if(Book->entry[pos].colour==Black){ - black_pos_extended++; - } - } - white_pos_extended_diff=white_pos_extended-white_pos; - black_pos_extended_diff=black_pos_extended-black_pos; - printf("Unreachable white positions(?) : %8d\n", - white_pos_extended_diff); - printf("Unreachable black positions(?) : %8d\n", - black_pos_extended_diff); - - } - if(extended_search){ - printf("Isolated positions : %8d\n", - total_pos-white_pos_extended-black_pos_extended); - }else{ - printf("Isolated positions : %8d\n", - total_pos-white_pos-black_pos); - } -} - - - -// end of book_make.cpp - +// book_make.c + +// includes + +#include +#include +#include +#include +#include + +#include "board.h" +#include "book_make.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "pgn.h" +#include "san.h" +#include "util.h" + +// constants + +#define COUNT_MAX ((int)16384) + +static const int NIL = -1; + +// defines + +#define opp_search(s) ((s)==BOOK?ALL:BOOK) + +// types + +typedef struct { + uint64 key; + uint16 move; + uint16 count; +// Unfortunately the minggw32 cross compiler [4.2.1-sjlj (mingw32-2)] +// seems to have a bug with anon structs contained in unions when using -O2. +// See the ASSERT below in "read_entry_file"... +// To be fair this seems to be illegal in C++ +// although it is hard to understand why, and the compiler does not complain +// even with -Wall. +// union { +// struct { + uint16 n; + uint16 sum; +// }; +// struct { + uint8 height; + int line; +// }; +// }; + uint8 colour; +} entry_t; + +typedef struct { + int size; + int alloc; + uint32 mask; + entry_t * entry; + sint32 * hash; +} book_t; + +typedef enum { + BOOK, + ALL +} search_t; + +typedef struct { + int height; + int line; + int initial_color; + bool book_trans_only; + bool extended_search; + uint16 moves[1024]; + double probs[1024]; + uint64 keys[1024]; + FILE *output; +} info_t; + + +// variables + +static int MaxPly; +static int MinGame; +static double MinScore; +static bool RemoveWhite, RemoveBlack; +static bool Uniform; +static bool Quiet=FALSE; + +static book_t Book[1]; + +// prototypes + +static void book_clear (); +static void book_insert (const char file_name[]); +static void book_filter (); +static void book_sort (); +static void book_save (const char file_name[]); + +static int find_entry (const board_t * board, int move); +static void resize (); +static void halve_stats (uint64 key); + +static bool keep_entry (int pos); + +static int entry_score (const entry_t * entry); + +static int key_compare (const void * p1, const void * p2); + +static void write_integer (FILE * file, int size, uint64 n); +static uint64 read_integer(FILE * file, int size); + +static void read_entry_file(FILE *f, entry_t *entry); +static void write_entry_file(FILE * f, const entry_t * entry); + +// functions + +// book_make() + +void book_make(int argc, char * argv[]) { + + int i; + const char * pgn_file; + const char * bin_file; + + pgn_file = NULL; + my_string_set(&pgn_file,"book.pgn"); + + bin_file = NULL; + my_string_set(&bin_file,"book.bin"); + + MaxPly = 1024; + MinGame = 3; + MinScore = 0.0; + RemoveWhite = FALSE; + RemoveBlack = FALSE; + Uniform = FALSE; + + for (i = 1; i < argc; i++) { + + if (FALSE) { + + } else if (my_string_equal(argv[i],"make-book")) { + + // skip + + } else if (my_string_equal(argv[i],"-pgn")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + my_string_set(&pgn_file,argv[i]); + + } else if (my_string_equal(argv[i],"-bin")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + my_string_set(&bin_file,argv[i]); + + } else if (my_string_equal(argv[i],"-max-ply")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + MaxPly = atoi(argv[i]); + ASSERT(MaxPly>=0); + + } else if (my_string_equal(argv[i],"-min-game")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + MinGame = atoi(argv[i]); + ASSERT(MinGame>0); + + } else if (my_string_equal(argv[i],"-min-score")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + MinScore = atof(argv[i]) / 100.0; + ASSERT(MinScore>=0.0&&MinScore<=1.0); + + } else if (my_string_equal(argv[i],"-only-white")) { + + RemoveWhite = FALSE; + RemoveBlack = TRUE; + + } else if (my_string_equal(argv[i],"-only-black")) { + + RemoveWhite = TRUE; + RemoveBlack = FALSE; + + } else if (my_string_equal(argv[i],"-uniform")) { + + Uniform = TRUE; + + } else { + + my_fatal("book_make(): unknown option \"%s\"\n",argv[i]); + } + } + + book_clear(); + + printf("inserting games ...\n"); + book_insert(pgn_file); + + printf("filtering entries ...\n"); + book_filter(); + + printf("sorting entries ...\n"); + book_sort(); + + printf("saving entries ...\n"); + book_save(bin_file); + + printf("all done!\n"); +} + +// book_clear() + +static void book_clear() { + + int index; + + Book->alloc = 1; + Book->mask = (Book->alloc * 2) - 1; + + Book->entry = (entry_t *) my_malloc(Book->alloc*sizeof(entry_t)); + Book->size = 0; + + Book->hash = (sint32 *) my_malloc((Book->alloc*2)*sizeof(sint32)); + for (index = 0; index < Book->alloc*2; index++) { + Book->hash[index] = NIL; + } +} + +// book_insert() + +static void book_insert(const char file_name[]) { + + pgn_t pgn[1]; + board_t board[1]; + int ply; + int result; + char string[256]; + int move; + int pos; + + ASSERT(file_name!=NULL); + + // init + + pgn->game_nb=1; + // scan loop + + pgn_open(pgn,file_name); + + while (pgn_next_game(pgn)) { + + board_start(board); + ply = 0; + result = 0; + + if (FALSE) { + } else if (my_string_equal(pgn->result,"1-0")) { + result = +1; + } else if (my_string_equal(pgn->result,"0-1")) { + result = -1; + } + + while (pgn_next_move(pgn,string,256)) { + + if (ply < MaxPly) { + + move = move_from_san(string,board); + + if (move == MoveNone || !move_is_legal(move,board)) { + my_fatal("book_insert(): illegal move \"%s\" at line %d, column %d,game %d\n",string,pgn->move_line,pgn->move_column,pgn->game_nb); + } + + pos = find_entry(board,move); + + Book->entry[pos].n++; + Book->entry[pos].sum += result+1; + + if (Book->entry[pos].n >= COUNT_MAX) { + halve_stats(board->key); + } + + move_do(board,move); + ply++; + result = -result; + } + } + pgn->game_nb++; + if (pgn->game_nb % 10000 == 0) printf("%d games ...\n",pgn->game_nb); + } + + pgn_close(pgn); + + printf("%d game%s.\n",pgn->game_nb,(pgn->game_nb>2)?"s":""); + printf("%d entries.\n",Book->size); + + return; +} + +// book_filter() + +static void book_filter() { + + int src, dst; + + // entry loop + + dst = 0; + + for (src = 0; src < Book->size; src++) { + if (keep_entry(src)) Book->entry[dst++] = Book->entry[src]; + } + + ASSERT(dst>=0&&dst<=Book->size); + Book->size = dst; + + printf("%d entries.\n",Book->size); +} + +// book_sort() + +static void book_sort() { + + // sort keys for binary search + + qsort(Book->entry,Book->size,sizeof(entry_t),&key_compare); +} + +// book_save() + +static void book_save(const char file_name[]) { + + FILE * file; + int pos; + + ASSERT(file_name!=NULL); + + file = fopen(file_name,"wb"); + if (file == NULL) my_fatal("book_save(): can't open file \"%s\" for writing: %s\n",file_name,strerror(errno)); + + // entry loop + + for (pos = 0; pos < Book->size; pos++) { + + ASSERT(keep_entry(pos)); + + write_integer(file,8,Book->entry[pos].key); + write_integer(file,2,Book->entry[pos].move); + write_integer(file,2,entry_score(&Book->entry[pos])); + write_integer(file,2,0); + write_integer(file,2,0); + } + + fclose(file); +} + +// find_entry() + +static int find_entry(const board_t * board, int move) { + + uint64 key; + int index; + int pos; + + ASSERT(board!=NULL); + ASSERT(move==MoveNone || move_is_ok(move)); + + ASSERT(move==MoveNone || move_is_legal(move,board)); + + // init + + key = board->key; + + // search + + for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { + + ASSERT(pos>=0&&possize); + + if (Book->entry[pos].key == key && Book->entry[pos].move == move) { + return pos; // found + } + } + + // not found + + ASSERT(Book->size<=Book->alloc); + + if (Book->size == Book->alloc) { + + // allocate more memory + + resize(); + + for (index = key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask) + ; + } + + // create a new entry + + ASSERT(Book->sizealloc); + pos = Book->size++; + + Book->entry[pos].key = key; + Book->entry[pos].move = move; + Book->entry[pos].n = 0; + Book->entry[pos].sum = 0; + Book->entry[pos].colour = board->turn; + + // insert into the hash table + + ASSERT(index>=0&&indexalloc*2); + ASSERT(Book->hash[index]==NIL); + Book->hash[index] = pos; + + ASSERT(pos>=0&&possize); + + return pos; +} + +// rebuild_hash_table + +static void rebuild_hash_table(){ + int index,pos; + for (index = 0; index < Book->alloc*2; index++) { + Book->hash[index] = NIL; + } + for (pos = 0; pos < Book->size; pos++) { + for (index = Book->entry[pos].key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask) + ; + ASSERT(index>=0&&indexalloc*2); + Book->hash[index] = pos; + } +} + +static void resize() { + + int size; + + ASSERT(Book->size==Book->alloc); + + Book->alloc *= 2; + Book->mask = (Book->alloc * 2) - 1; + + size = 0; + size += Book->alloc * sizeof(entry_t); + size += (Book->alloc*2) * sizeof(sint32); + + if (size >= 1048576) if(!Quiet){ + printf("allocating %gMB ...\n",((double)size)/1048576.0); + } + + // resize arrays + + Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t)); + Book->hash = (sint32 *) my_realloc(Book->hash,(Book->alloc*2)*sizeof(sint32)); + + // rebuild hash table + + rebuild_hash_table(); +} + + +// halve_stats() + +static void halve_stats(uint64 key) { + + int index; + int pos; + + // search + + for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { + + ASSERT(pos>=0&&possize); + + if (Book->entry[pos].key == key) { + Book->entry[pos].n = (Book->entry[pos].n + 1) / 2; + Book->entry[pos].sum = (Book->entry[pos].sum + 1) / 2; + } + } +} + +// keep_entry() + +static bool keep_entry(int pos) { + + const entry_t * entry; + int colour; + double score; + + ASSERT(pos>=0&&possize); + + entry = &Book->entry[pos]; + + // if (entry->n == 0) return FALSE; + if (entry->n < MinGame) return FALSE; + + if (entry->sum == 0) return FALSE; + + score = (((double)entry->sum) / ((double)entry->n)) / 2.0; + ASSERT(score>=0.0&&score<=1.0); + + if (score < MinScore) return FALSE; + + colour = entry->colour; + + if ((RemoveWhite && colour_is_white(colour)) + || (RemoveBlack && colour_is_black(colour))) { + return FALSE; + } + + if (entry_score(entry) == 0) return FALSE; // REMOVE ME? + + return TRUE; +} + +// entry_score() + +static int entry_score(const entry_t * entry) { + + int score; + + ASSERT(entry!=NULL); + + // score = entry->n; // popularity + score = entry->sum; // "expectancy" + + if (Uniform) score = 1; + + ASSERT(score>=0); + + return score; +} + +// key_compare() + +static int key_compare(const void * p1, const void * p2) { + + const entry_t * entry_1, * entry_2; + + ASSERT(p1!=NULL); + ASSERT(p2!=NULL); + + entry_1 = (const entry_t *) p1; + entry_2 = (const entry_t *) p2; + + if (entry_1->key > entry_2->key) { + return +1; + } else if (entry_1->key < entry_2->key) { + return -1; + } else { + return entry_score(entry_2) - entry_score(entry_1); // highest score first + } +} + +// write_integer() + +static void write_integer(FILE * file, int size, uint64 n) { + + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + ASSERT(size==8||n>>(size*8)==0); + + for (i = size-1; i >= 0; i--) { + b = (n >> (i*8)) & 0xFF; + ASSERT(b>=0&&b<256); + fputc(b,file); + } +} + +// read_integer() + +static uint64 read_integer(FILE * file, int size) { + uint64 n; + int i; + int b; + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + n = 0; + for (i = 0; i < size; i++) { + b = fgetc(file); + if (b == EOF) { + if (feof(file)) { + my_fatal("read_integer(): fgetc(): EOF reached\n"); + } else { // error + my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); + } + } + ASSERT(b>=0&&b<256); + n = (n << 8) | b; + } + return n; +} + +// read_entry_file + +static void read_entry_file(FILE *f, entry_t *entry){ + uint64 n; + ASSERT(entry!=NULL); + n = entry->key = read_integer(f,8); + entry->move = read_integer(f,2); + entry->count = read_integer(f,2); + entry->n = read_integer(f,2); + entry->sum = read_integer(f,2); + ASSERT(n==entry->key); // test for mingw compiler bug with anon structs +} + +// write_entry_file + +static void write_entry_file(FILE * f, const entry_t * entry) { + ASSERT(entry!=NULL); + write_integer(f,8,entry->key); + write_integer(f,2,entry->move); + write_integer(f,2,entry->count); + write_integer(f,2,entry->n); + write_integer(f,2,entry->sum); +} + +static void print_list(const board_t *board, list_t *list){ + int i; + uint16 move; + char move_string[256]; + for (i = 0; i < list_size(list); i++) { + move = list_move(list,i); + move_to_san(move,board,move_string,256); + printf("%s",move_string); + } + printf("\n"); +} + +// book_load() +// loads a polyglot book + +static void book_load(const char filename[]){ + FILE* f; + entry_t entry[1]; + int size; + int i; + int pos; + int index; + ASSERT(filename!=NULL); + if(!(f=fopen(filename,"rb"))){ + my_fatal("book_load() : can't open file \"%s\" for reading: %s\n",filename,strerror(errno)); + } + fseek(f,0L,SEEK_END); // superportable way to get size of book! + size=ftell(f)/16; + fseek(f,0,SEEK_SET); + for(i=0L;isize<=Book->alloc); + if (Book->size == Book->alloc) { + // allocate more memoryx + resize(); + } + // insert into the book + pos = Book->size++; + Book->entry[pos].key = entry->key; + ASSERT(entry->move!=MoveNone); + Book->entry[pos].move = entry->move; + Book->entry[pos].count = entry->count; + Book->entry[pos].n = entry->n; + Book->entry[pos].sum = entry->sum; + Book->entry[pos].colour = ColourNone; + // find free hash table spot + for (index = entry->key & (uint64) Book->mask; + Book->hash[index] != NIL; + index = (index+1) & Book->mask); + // insert into the hash table + ASSERT(index>=0&&indexalloc*2); + ASSERT(Book->hash[index]==NIL); + Book->hash[index] = pos; + ASSERT(pos>=0&&possize); + } + fclose(f); +} + +// gen_book_moves() +// similar signature as gen_legal_moves +static int gen_book_moves(list_t * list, const board_t * board){ + int first_pos, pos, index; + entry_t entry[1]; + bool found; + list_clear(list); + found=FALSE; + for (index = board->key & (uint64) Book->mask; (first_pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { + ASSERT(first_pos>=0&&first_possize); + if (Book->entry[first_pos].key == board->key) { + found=TRUE; + break; // found + } + } + if(!found) return -1; + if(Book->entry[first_pos].move==MoveNone) return -1; + for (pos = first_pos; pos < Book->size; pos++) { + *entry=Book->entry[pos]; + if (entry->key != board->key) break; + if (entry->count > 0 && + entry->move != MoveNone && + move_is_legal(entry->move,board)) { + list_add_ex(list,entry->move,entry->count); + } + } + return first_pos; +} + +// gen_opp_book_moves() +// moves to which opponent has a reply in book +// similar signature as gen_legal_moves +static void gen_opp_book_moves(list_t * list, const board_t * board){ + int move; + list_t new_list[1], legal_moves[1]; + board_t new_board[1]; + int i; + list_clear(list); + gen_legal_moves(legal_moves,board); + for (i = 0; i < list_size(legal_moves); i++) { + move = list_move(legal_moves,i); + // scratch_board + memcpy(new_board, board, sizeof(board_t)); + move_do(new_board,move); + gen_book_moves(new_list,new_board); // wasteful in time but tested! + if(list_size(new_list)!=0){ + list_add(list,move); + } + } +} + +static void print_moves(info_t *info){ + board_t board[1]; + char move_string[256]; + int i; + int color=White; + if(!info->output){ + return; + } + board_start(board); + for(i=0;iheight;i++){ + if(color==White){ + fprintf(info->output,"%d. ",i/2+1); + color=Black; + }else{ + color=White; + } + move_to_san(info->moves[i],board,move_string,256); + fprintf(info->output,"%s", move_string); + if(color==colour_opp(info->initial_color)){ + fprintf(info->output,"{%.0f%%} ",100*info->probs[i]); + }else{ + fprintf(info->output," "); + } + move_do(board,info->moves[i]); + } +} + +static int search_book(board_t *board, info_t *info, search_t search){ + list_t list[1]; + board_t new_board[1]; + uint16 move; + int count; + int ret; + int i; + int offset; + int pos; + int size; + int prob_sum; + double probs[256]; + for(i=0;i<256;i++){ + probs[i]=0.0; // kill compiler warnings + } + for(i=0;iheight;i++){ + if(board->key==info->keys[i]){ + if(info->output){ + fprintf(info->output,"%d: ",info->line); + print_moves(info); + fprintf(info->output,"{cycle: ply=%d}\n",i); + } + info->line++; + return 1; // end of line because of cycle + } + } + if(!info->book_trans_only || (info->book_trans_only && search==BOOK)){ + info->keys[info->height]=board->key; + size=Book->size; // hack + pos=find_entry(board,MoveNone); + if(size==Book->size){ + if(info->output){ + fprintf(info->output,"%d: ",info->line); + print_moves(info); + fprintf(info->output,"{trans: line=%d, ply=%d}\n", + Book->entry[pos].line, + Book->entry[pos].height); + } + info->line++; + return 1; // end of line because of transposition + }else{ + Book->entry[pos].height=info->height; + Book->entry[pos].line=info->line; + } + } + count=0; + if(search==BOOK){ + offset=gen_book_moves(list,board); + if(info->extended_search){ + gen_legal_moves(list,board); + } +// ASSERT(offset!=-1); + if(offset!=-1){ // only FALSE in starting position for black book + Book->entry[offset].colour=board->turn; + prob_sum=0; + if(!info->extended_search){ + for(i=0;imoves[info->height++]=move; + if(search==BOOK){ + info->probs[info->height-1]=probs[i]; + } + ret=search_book(new_board, info, opp_search(search)); + if(ret==0 && search==BOOK){ + if(info->output){ + fprintf(info->output,"%d: ",info->line); + print_moves(info); + fprintf(info->output,"\n"); + } + info->line++; + ret=1; // end of line book move counts for 1 + } + info->height--; + ASSERT(info->height>=0); + count+=ret; + } + return count; +} + +void init_info(info_t *info){ + info->line=1; + info->height=0; + info->output=NULL; + info->initial_color=White; + info->book_trans_only=FALSE; +} + +// book_clean() +// remove MoveNone entries from book and rebuild hash table +void book_clean(){ + int read_ptr,write_ptr; + write_ptr=0; + for(read_ptr=0;read_ptrsize;read_ptr++){ + if(Book->entry[read_ptr].move!=MoveNone){ + Book->entry[write_ptr++]=Book->entry[read_ptr]; + } + } + Book->size=write_ptr; + rebuild_hash_table(); +} + +// book_dump() + +void book_dump(int argc, char * argv[]) { + const char * bin_file=NULL; + const char * txt_file=NULL; + char string[StringSize]; + int color=ColourNone; + board_t board[1]; + info_t info[1]; + int i; + FILE *f; + my_string_set(&bin_file,"book.bin"); + for (i = 1; i < argc; i++) { + if (FALSE) { + } else if (my_string_equal(argv[i],"dump-book")) { + // skip + } else if (my_string_equal(argv[i],"-bin")) { + i++; + if (i==argc) my_fatal("book_dump(): missing argument\n"); + my_string_set(&bin_file,argv[i]); + } else if (my_string_equal(argv[i],"-out")) { + i++; + if (i==argc) my_fatal("book_dump(): missing argument\n"); + my_string_set(&txt_file,argv[i]); + } else if (my_string_equal(argv[i],"-color") || my_string_equal(argv[i],"-colour")) { + i++; + if (i == argc) my_fatal("book_dump(): missing argument\n"); + if(my_string_equal(argv[i],"white")){ + color=White; + }else if (my_string_equal(argv[i],"black")){ + color=Black; + }else{ + my_fatal("book_dump(): unknown color \"%s\"\n",argv[i]); + } + } else { + my_fatal("book_dump(): unknown option \"%s\"\n",argv[i]); + } + } + if(color==ColourNone){ + my_fatal("book_dump(): you must specify a color\n"); + } + if(txt_file==NULL){ + snprintf(string,StringSize,"book_%s.txt",color?"white":"black"); + my_string_set(&txt_file,string); + } + + book_clear(); + if(!Quiet){printf("loading book ...\n");} + book_load(bin_file); + board_start(board); + init_info(info); + info->initial_color=color; + if(!(f=fopen(txt_file,"w"))){ + my_fatal("book_dump(): can't open file \"%s\" for writing: %s", + txt_file,strerror(errno)); + } + info->output=f; + fprintf(info->output,"Dump of \"%s\" for %s.\n", + bin_file,color==White?"white":"black"); + if(color==White){ + if(!Quiet){printf("generating lines for white...\n");} + search_book(board,info, BOOK); + }else{ + if(!Quiet){printf("generating lines for black...\n");} + search_book(board,info, ALL); + } +} + +// book_info() + +void book_info(int argc,char* argv[]){ + const char *bin_file=NULL; + board_t board[1]; + info_t info[1]; + uint64 last_key; + int pos; + int white_pos,black_pos,total_pos,white_pos_extended, + black_pos_extended,white_pos_extended_diff,black_pos_extended_diff; + int s; + bool extended_search=FALSE; + int i; + Quiet=TRUE; + my_string_set(&bin_file,"book.bin"); + + for (i = 1; i < argc; i++) { + if (FALSE) { + } else if (my_string_equal(argv[i],"info-book")) { + // skip + } else if (my_string_equal(argv[i],"-bin")) { + i++; + if (i==argc) my_fatal("book_info(): missing argument\n"); + my_string_set(&bin_file,argv[i]); + } else if (my_string_equal(argv[i],"-exact")) { + extended_search=TRUE; + } else { + my_fatal("book_info(): unknown option \"%s\"\n",argv[i]); + } + } + book_clear(); + if(!Quiet){printf("loading book ...\n");} + book_load(bin_file); + s=Book->size; + + board_start(board); + init_info(info); + info->book_trans_only=FALSE; + info->initial_color=White; + info->extended_search=FALSE; + search_book(board,info, BOOK); + printf("Lines for white : %8d\n",info->line-1); + + + info->line=1; + info->height=0; + info->initial_color=Black; + book_clean(); + ASSERT(Book->size==s); + board_start(board); + search_book(board,info, ALL); + printf("Lines for black : %8d\n",info->line-1); + + book_clean(); + ASSERT(Book->size==s); + white_pos=0; + black_pos=0; + total_pos=0; + last_key=0; + for(pos=0;possize;pos++){ + if(Book->entry[pos].key==last_key){ + ASSERT(Book->entry[pos].colour==ColourNone); + continue; + } + last_key=Book->entry[pos].key; + total_pos++; + if(Book->entry[pos].colour==White){ + white_pos++; + }else if(Book->entry[pos].colour==Black){ + black_pos++; + } + } + printf("Positions on lines for white : %8d\n",white_pos); + printf("Positions on lines for black : %8d\n",black_pos); + + + if(extended_search){ + init_info(info); + info->book_trans_only=TRUE; + info->initial_color=White; + info->extended_search=TRUE; + book_clean(); + board_start(board); + search_book(board,info, BOOK); + + init_info(info); + info->book_trans_only=TRUE; + info->initial_color=Black; + info->extended_search=TRUE; + book_clean(); + board_start(board); + search_book(board,info, ALL); + book_clean(); + ASSERT(Book->size==s); + white_pos_extended=0; + black_pos_extended=0; + last_key=0; + for(pos=0;possize;pos++){ + if(Book->entry[pos].key==last_key){ + ASSERT(Book->entry[pos].colour==ColourNone); + continue; + } + last_key=Book->entry[pos].key; + if(Book->entry[pos].colour==White){ + white_pos_extended++; + }else if(Book->entry[pos].colour==Black){ + black_pos_extended++; + } + } + white_pos_extended_diff=white_pos_extended-white_pos; + black_pos_extended_diff=black_pos_extended-black_pos; + printf("Unreachable white positions(?) : %8d\n", + white_pos_extended_diff); + printf("Unreachable black positions(?) : %8d\n", + black_pos_extended_diff); + + } + if(extended_search){ + printf("Isolated positions : %8d\n", + total_pos-white_pos_extended-black_pos_extended); + }else{ + printf("Isolated positions : %8d\n", + total_pos-white_pos-black_pos); + } +} + + + +// end of book_make.cpp + diff --git a/book_make.h b/book_make.h index f4054c0..41bf6df 100644 --- a/book_make.h +++ b/book_make.h @@ -1,20 +1,20 @@ - -// book_make.h - -#ifndef BOOK_MAKE_H -#define BOOK_MAKE_H - -// includes - -#include "util.h" - -// functions - -extern void book_make (int argc, char * argv[]); -extern void book_dump (int argc, char * argv[]); -extern void book_info (int argc, char * argv[]); - -#endif // !defined BOOK_MAKE_H - -// end of book_make.h - + +// book_make.h + +#ifndef BOOK_MAKE_H +#define BOOK_MAKE_H + +// includes + +#include "util.h" + +// functions + +extern void book_make (int argc, char * argv[]); +extern void book_dump (int argc, char * argv[]); +extern void book_info (int argc, char * argv[]); + +#endif // !defined BOOK_MAKE_H + +// end of book_make.h + diff --git a/book_merge.c b/book_merge.c index f68e2cc..ee2d848 100644 --- a/book_merge.c +++ b/book_merge.c @@ -1,304 +1,304 @@ - -// book_merge.c - -// includes - -#include -#include -#include -#include - -#include "book_merge.h" -#include "util.h" - -// types - -typedef struct { - FILE * file; - int size; -} book_t; - -typedef struct { - uint64 key; - uint16 move; - uint16 count; - uint16 n; - uint16 sum; -} entry_t; - -// variables - -static book_t In1[1]; -static book_t In2[1]; -static book_t Out[1]; - -// prototypes - -static void book_clear (book_t * book); - -static void book_open (book_t * book, const char file_name[], const char mode[]); -static void book_close (book_t * book); - -static bool read_entry (book_t * book, entry_t * entry, int n); -static void write_entry (book_t * book, const entry_t * entry); - -static uint64 read_integer (FILE * file, int size); -static void write_integer (FILE * file, int size, uint64 n); - -// functions - -// book_merge() - -void book_merge(int argc, char * argv[]) { - - int i; - const char * in_file_1; - const char * in_file_2; - const char * out_file; - int i1, i2; - bool b1, b2; - entry_t e1[1], e2[1]; - int skip; - - in_file_1 = NULL; - my_string_clear(&in_file_1); - - in_file_2 = NULL; - my_string_clear(&in_file_2); - - out_file = NULL; - my_string_set(&out_file,"out.bin"); - - for (i = 1; i < argc; i++) { - - if (FALSE) { - - } else if (my_string_equal(argv[i],"merge-book")) { - - // skip - - } else if (my_string_equal(argv[i],"-in1")) { - - i++; - if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); - - my_string_set(&in_file_1,argv[i]); - - } else if (my_string_equal(argv[i],"-in2")) { - - i++; - if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); - - my_string_set(&in_file_2,argv[i]); - - } else if (my_string_equal(argv[i],"-out")) { - - i++; - if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); - - my_string_set(&out_file,argv[i]); - - } else { - - my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]); - } - } - - book_clear(In1); - book_clear(In2); - book_clear(Out); - - book_open(In1,in_file_1,"rb"); - book_open(In2,in_file_2,"rb"); - book_open(Out,out_file,"wb"); - - skip = 0; - - i1 = 0; - i2 = 0; - - while (TRUE) { - - b1 = read_entry(In1,e1,i1); - b2 = read_entry(In2,e2,i2); - - if (FALSE) { - - } else if (!b1 && !b2) { - - break; - - } else if (b1 && !b2) { - - write_entry(Out,e1); - i1++; - - } else if (b2 && !b1) { - - write_entry(Out,e2); - i2++; - - } else { - - ASSERT(b1); - ASSERT(b2); - - if (FALSE) { - } else if (e1->key < e2->key) { - write_entry(Out,e1); - i1++; - } else if (e1->key > e2->key) { - write_entry(Out,e2); - i2++; - } else { - ASSERT(e1->key==e2->key); - skip++; - i2++; - } - } - } - - book_close(In1); - book_close(In2); - book_close(Out); - - if (skip != 0) { - printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y"); - } - - printf("done!\n"); -} - -// book_clear() - -static void book_clear(book_t * book) { - - ASSERT(book!=NULL); - - book->file = NULL; - book->size = 0; -} - -// book_open() - -static void book_open(book_t * book, const char file_name[], const char mode[]) { - - ASSERT(book!=NULL); - ASSERT(file_name!=NULL); - ASSERT(mode!=NULL); - - book->file = fopen(file_name,mode); - if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); - - if (fseek(book->file,0,SEEK_END) == -1) { - my_fatal("book_open(): fseek(): %s\n",strerror(errno)); - } - - book->size = ftell(book->file) / 16; -} - -// book_close() - -static void book_close(book_t * book) { - - ASSERT(book!=NULL); - - if (fclose(book->file) == EOF) { - my_fatal("book_close(): fclose(): %s\n",strerror(errno)); - } -} - -// read_entry() - -static bool read_entry(book_t * book, entry_t * entry, int n) { - - ASSERT(book!=NULL); - ASSERT(entry!=NULL); - - if (n < 0 || n >= book->size) return FALSE; - - ASSERT(n>=0&&nsize); - - if (fseek(book->file,n*16,SEEK_SET) == -1) { - my_fatal("read_entry(): fseek(): %s\n",strerror(errno)); - } - - entry->key = read_integer(book->file,8); - entry->move = read_integer(book->file,2); - entry->count = read_integer(book->file,2); - entry->n = read_integer(book->file,2); - entry->sum = read_integer(book->file,2); - - return TRUE; -} - -// write_entry() - -static void write_entry(book_t * book, const entry_t * entry) { - - ASSERT(book!=NULL); - ASSERT(entry!=NULL); - - write_integer(book->file,8,entry->key); - write_integer(book->file,2,entry->move); - write_integer(book->file,2,entry->count); - write_integer(book->file,2,entry->n); - write_integer(book->file,2,entry->sum); -} - -// read_integer() - -static uint64 read_integer(FILE * file, int size) { - - uint64 n; - int i; - int b; - - ASSERT(file!=NULL); - ASSERT(size>0&&size<=8); - - n = 0; - - for (i = 0; i < size; i++) { - - b = fgetc(file); - - if (b == EOF) { - if (feof(file)) { - my_fatal("read_integer(): fgetc(): EOF reached\n"); - } else { // error - my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); - } - } - - ASSERT(b>=0&&b<256); - n = (n << 8) | b; - } - - return n; -} - -// write_integer() - -static void write_integer(FILE * file, int size, uint64 n) { - - int i; - int b; - - ASSERT(file!=NULL); - ASSERT(size>0&&size<=8); - ASSERT(size==8||n>>(size*8)==0); - - for (i = size-1; i >= 0; i--) { - - b = (n >> (i*8)) & 0xFF; - ASSERT(b>=0&&b<256); - - if (fputc(b,file) == EOF) { - my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); - } - } -} - -// end of book_merge.cpp - + +// book_merge.c + +// includes + +#include +#include +#include +#include + +#include "book_merge.h" +#include "util.h" + +// types + +typedef struct { + FILE * file; + int size; +} book_t; + +typedef struct { + uint64 key; + uint16 move; + uint16 count; + uint16 n; + uint16 sum; +} entry_t; + +// variables + +static book_t In1[1]; +static book_t In2[1]; +static book_t Out[1]; + +// prototypes + +static void book_clear (book_t * book); + +static void book_open (book_t * book, const char file_name[], const char mode[]); +static void book_close (book_t * book); + +static bool read_entry (book_t * book, entry_t * entry, int n); +static void write_entry (book_t * book, const entry_t * entry); + +static uint64 read_integer (FILE * file, int size); +static void write_integer (FILE * file, int size, uint64 n); + +// functions + +// book_merge() + +void book_merge(int argc, char * argv[]) { + + int i; + const char * in_file_1; + const char * in_file_2; + const char * out_file; + int i1, i2; + bool b1, b2; + entry_t e1[1], e2[1]; + int skip; + + in_file_1 = NULL; + my_string_clear(&in_file_1); + + in_file_2 = NULL; + my_string_clear(&in_file_2); + + out_file = NULL; + my_string_set(&out_file,"out.bin"); + + for (i = 1; i < argc; i++) { + + if (FALSE) { + + } else if (my_string_equal(argv[i],"merge-book")) { + + // skip + + } else if (my_string_equal(argv[i],"-in1")) { + + i++; + if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); + + my_string_set(&in_file_1,argv[i]); + + } else if (my_string_equal(argv[i],"-in2")) { + + i++; + if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); + + my_string_set(&in_file_2,argv[i]); + + } else if (my_string_equal(argv[i],"-out")) { + + i++; + if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); + + my_string_set(&out_file,argv[i]); + + } else { + + my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]); + } + } + + book_clear(In1); + book_clear(In2); + book_clear(Out); + + book_open(In1,in_file_1,"rb"); + book_open(In2,in_file_2,"rb"); + book_open(Out,out_file,"wb"); + + skip = 0; + + i1 = 0; + i2 = 0; + + while (TRUE) { + + b1 = read_entry(In1,e1,i1); + b2 = read_entry(In2,e2,i2); + + if (FALSE) { + + } else if (!b1 && !b2) { + + break; + + } else if (b1 && !b2) { + + write_entry(Out,e1); + i1++; + + } else if (b2 && !b1) { + + write_entry(Out,e2); + i2++; + + } else { + + ASSERT(b1); + ASSERT(b2); + + if (FALSE) { + } else if (e1->key < e2->key) { + write_entry(Out,e1); + i1++; + } else if (e1->key > e2->key) { + write_entry(Out,e2); + i2++; + } else { + ASSERT(e1->key==e2->key); + skip++; + i2++; + } + } + } + + book_close(In1); + book_close(In2); + book_close(Out); + + if (skip != 0) { + printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y"); + } + + printf("done!\n"); +} + +// book_clear() + +static void book_clear(book_t * book) { + + ASSERT(book!=NULL); + + book->file = NULL; + book->size = 0; +} + +// book_open() + +static void book_open(book_t * book, const char file_name[], const char mode[]) { + + ASSERT(book!=NULL); + ASSERT(file_name!=NULL); + ASSERT(mode!=NULL); + + book->file = fopen(file_name,mode); + if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + + if (fseek(book->file,0,SEEK_END) == -1) { + my_fatal("book_open(): fseek(): %s\n",strerror(errno)); + } + + book->size = ftell(book->file) / 16; +} + +// book_close() + +static void book_close(book_t * book) { + + ASSERT(book!=NULL); + + if (fclose(book->file) == EOF) { + my_fatal("book_close(): fclose(): %s\n",strerror(errno)); + } +} + +// read_entry() + +static bool read_entry(book_t * book, entry_t * entry, int n) { + + ASSERT(book!=NULL); + ASSERT(entry!=NULL); + + if (n < 0 || n >= book->size) return FALSE; + + ASSERT(n>=0&&nsize); + + if (fseek(book->file,n*16,SEEK_SET) == -1) { + my_fatal("read_entry(): fseek(): %s\n",strerror(errno)); + } + + entry->key = read_integer(book->file,8); + entry->move = read_integer(book->file,2); + entry->count = read_integer(book->file,2); + entry->n = read_integer(book->file,2); + entry->sum = read_integer(book->file,2); + + return TRUE; +} + +// write_entry() + +static void write_entry(book_t * book, const entry_t * entry) { + + ASSERT(book!=NULL); + ASSERT(entry!=NULL); + + write_integer(book->file,8,entry->key); + write_integer(book->file,2,entry->move); + write_integer(book->file,2,entry->count); + write_integer(book->file,2,entry->n); + write_integer(book->file,2,entry->sum); +} + +// read_integer() + +static uint64 read_integer(FILE * file, int size) { + + uint64 n; + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + + n = 0; + + for (i = 0; i < size; i++) { + + b = fgetc(file); + + if (b == EOF) { + if (feof(file)) { + my_fatal("read_integer(): fgetc(): EOF reached\n"); + } else { // error + my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); + } + } + + ASSERT(b>=0&&b<256); + n = (n << 8) | b; + } + + return n; +} + +// write_integer() + +static void write_integer(FILE * file, int size, uint64 n) { + + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + ASSERT(size==8||n>>(size*8)==0); + + for (i = size-1; i >= 0; i--) { + + b = (n >> (i*8)) & 0xFF; + ASSERT(b>=0&&b<256); + + if (fputc(b,file) == EOF) { + my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); + } + } +} + +// end of book_merge.cpp + diff --git a/book_merge.h b/book_merge.h index d53e3d0..0ccbc6e 100644 --- a/book_merge.h +++ b/book_merge.h @@ -1,18 +1,18 @@ - -// book_merge.h - -#ifndef BOOK_MERGE_H -#define BOOK_MERGE_H - -// includes - -#include "util.h" - -// functions - -extern void book_merge (int argc, char * argv[]); - -#endif // !defined BOOK_MERGE_H - -// end of book_merge.h - + +// book_merge.h + +#ifndef BOOK_MERGE_H +#define BOOK_MERGE_H + +// includes + +#include "util.h" + +// functions + +extern void book_merge (int argc, char * argv[]); + +#endif // !defined BOOK_MERGE_H + +// end of book_merge.h + diff --git a/colour.c b/colour.c index e0936b9..b93f802 100644 --- a/colour.c +++ b/colour.c @@ -1,55 +1,55 @@ - -// colour.c - -// includes - -#include "colour.h" -#include "util.h" - -// functions - -// colour_is_ok() - -bool colour_is_ok(int colour) { - - return colour == Black || colour == White; -} - -// colour_is_white() - -bool colour_is_white(int colour) { - - ASSERT(colour_is_ok(colour)); - - return colour == White; -} - -// colour_is_black() - -bool colour_is_black(int colour) { - - ASSERT(colour_is_ok(colour)); - - return colour == Black; -} - -// colour_equal() - -bool colour_equal(int colour_1, int colour_2) { - - ASSERT(colour_is_ok(colour_2)); - - return (colour_1 & colour_2) != 0; -} - -// colour_opp() - -int colour_opp(int colour) { - - ASSERT(colour_is_ok(colour)); - - return colour ^ (BlackFlag^WhiteFlag); -} - -// end of colour.cpp - + +// colour.c + +// includes + +#include "colour.h" +#include "util.h" + +// functions + +// colour_is_ok() + +bool colour_is_ok(int colour) { + + return colour == Black || colour == White; +} + +// colour_is_white() + +bool colour_is_white(int colour) { + + ASSERT(colour_is_ok(colour)); + + return colour == White; +} + +// colour_is_black() + +bool colour_is_black(int colour) { + + ASSERT(colour_is_ok(colour)); + + return colour == Black; +} + +// colour_equal() + +bool colour_equal(int colour_1, int colour_2) { + + ASSERT(colour_is_ok(colour_2)); + + return (colour_1 & colour_2) != 0; +} + +// colour_opp() + +int colour_opp(int colour) { + + ASSERT(colour_is_ok(colour)); + + return colour ^ (BlackFlag^WhiteFlag); +} + +// end of colour.cpp + diff --git a/colour.h b/colour.h index 82a7d7b..b1c6b14 100644 --- a/colour.h +++ b/colour.h @@ -1,33 +1,33 @@ - -// colour.h - -#ifndef COLOUR_H -#define COLOUR_H - -// includes - -#include "util.h" - -// defines - -#define BlackFlag (1 << 0) -#define WhiteFlag (1 << 1) -#define ColourNone 0 -#define Black BlackFlag -#define White WhiteFlag -#define ColourNb 3 - -// functions - -extern bool colour_is_ok (int colour); - -extern bool colour_is_white (int colour); -extern bool colour_is_black (int colour); -extern bool colour_equal (int colour_1, int colour_2); - -extern int colour_opp (int colour); - -#endif // !defined COLOUR_H - -// end of colour.h - + +// colour.h + +#ifndef COLOUR_H +#define COLOUR_H + +// includes + +#include "util.h" + +// defines + +#define BlackFlag (1 << 0) +#define WhiteFlag (1 << 1) +#define ColourNone 0 +#define Black BlackFlag +#define White WhiteFlag +#define ColourNb 3 + +// functions + +extern bool colour_is_ok (int colour); + +extern bool colour_is_white (int colour); +extern bool colour_is_black (int colour); +extern bool colour_equal (int colour_1, int colour_2); + +extern int colour_opp (int colour); + +#endif // !defined COLOUR_H + +// end of colour.h + diff --git a/config.h b/config.h index 5e50316..589c256 100644 --- a/config.h +++ b/config.h @@ -115,7 +115,7 @@ #define PACKAGE_NAME "polyglot" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "polyglot 1.4.61b" +#define PACKAGE_STRING "polyglot 1.4.63b" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "polyglot" @@ -124,7 +124,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.4.61b" +#define PACKAGE_VERSION "1.4.63b" /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void @@ -145,7 +145,7 @@ #define TIME_WITH_SYS_TIME 1 /* Version number of package */ -#define VERSION "1.4.61b" +#define VERSION "1.4.63b" /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ diff --git a/configure b/configure index 4a88735..e1d9e6e 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.64 for polyglot 1.4.61b. +# Generated by GNU Autoconf 2.64 for polyglot 1.4.63b. # # Report bugs to . # @@ -549,8 +549,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='polyglot' PACKAGE_TARNAME='polyglot' -PACKAGE_VERSION='1.4.61b' -PACKAGE_STRING='polyglot 1.4.61b' +PACKAGE_VERSION='1.4.63b' +PACKAGE_STRING='polyglot 1.4.63b' PACKAGE_BUGREPORT='michel.vandenbergh@uhasselt.be' PACKAGE_URL='' @@ -1230,7 +1230,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures polyglot 1.4.61b to adapt to many kinds of systems. +\`configure' configures polyglot 1.4.63b to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1296,7 +1296,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of polyglot 1.4.61b:";; + short | recursive ) echo "Configuration of polyglot 1.4.63b:";; esac cat <<\_ACEOF @@ -1383,7 +1383,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -polyglot configure 1.4.61b +polyglot configure 1.4.63b generated by GNU Autoconf 2.64 Copyright (C) 2009 Free Software Foundation, Inc. @@ -1808,7 +1808,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by polyglot $as_me 1.4.61b, which was +It was created by polyglot $as_me 1.4.63b, which was generated by GNU Autoconf 2.64. Invocation command line was $ $0 $@ @@ -2616,7 +2616,7 @@ fi # Define the identity of the package. PACKAGE='polyglot' - VERSION='1.4.61b' + VERSION='1.4.63b' cat >>confdefs.h <<_ACEOF @@ -5388,7 +5388,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by polyglot $as_me 1.4.61b, which was +This file was extended by polyglot $as_me 1.4.63b, which was generated by GNU Autoconf 2.64. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5452,7 +5452,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -polyglot config.status 1.4.61b +polyglot config.status 1.4.63b configured by $0, generated by GNU Autoconf 2.64, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 09bc658..eb1b55e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([polyglot], [1.4.61b], [michel.vandenbergh@uhasselt.be]) +AC_INIT([polyglot], [1.4.63b], [michel.vandenbergh@uhasselt.be]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([mainloop.c]) AC_CONFIG_HEADER([config.h]) diff --git a/engine.c b/engine.c index af6555a..5ed6ed7 100644 --- a/engine.c +++ b/engine.c @@ -1,113 +1,112 @@ -// engine.c - -// includes - -#include -#include -#include -#include - -#include "engine.h" -#include "option.h" -#include "pipex.h" -#include "util.h" - -// variables - -engine_t Engine[1]; -#define StringSize ((int)4096) - -// functions - -// set_affinity() - -void set_affinity(engine_t *engine, int value){ - pipex_set_affinity(engine->pipex,value); -} - -// engine_set_nice_value() - -void engine_set_nice_value(engine_t *engine, int value){ - pipex_set_priority(engine->pipex,value); -} - -// engine_send_queue() - -void engine_send_queue(engine_t * engine, const char *format, ...) { - char buf[FormatBufferSize]; - CONSTRUCT_ARG_STRING(format,buf); - pipex_write(engine->pipex,buf); -} - -// engine_send() - -void engine_send(engine_t * engine, const char *format, ...) { - char buf[FormatBufferSize]; - CONSTRUCT_ARG_STRING(format,buf); - pipex_writeln(engine->pipex,buf); -} - -// engine_close() - -void engine_close(engine_t * engine){ - char string[StringSize]; - int elapsed_time; - int ret; - int close_timeout=500; - my_log("POLYGLOT Closing engine.\n"); - pipex_send_eof(engine->pipex); - // TODO: Timeout - - elapsed_time=0; - while (!engine_eof(engine) && (elapsed_time=close_timeout){ - my_log("POLYGLOT Waited more than %dms. Moving on.\n",close_timeout); - } - pipex_exit(engine->pipex,200); -} - -// engine_open() - -void engine_open(engine_t * engine){ - int affinity; - pipex_open(engine->pipex, - "Engine", - option_get_string(Option,"EngineDir"), - option_get_string(Option,"EngineCommand")); - if(pipex_active(engine->pipex)){ - //play with affinity (bad idea) - affinity=option_get_int(Option,"Affinity"); - if(affinity!=-1) set_affinity(engine,affinity); //AAA - // set a low priority - if (option_get_bool(Option,"UseNice")){ - my_log("POLYGLOT Adjust Engine Piority\n"); - engine_set_nice_value(engine, option_get_int(Option,"NiceValue")); - } - } - -} - -bool engine_active(engine_t *engine){ - return pipex_active(engine->pipex); -} - -bool engine_eof(engine_t *engine){ - return pipex_eof(engine->pipex); -} - -bool engine_get_non_blocking(engine_t * engine, char *string){ - return pipex_readln_nb(engine->pipex,string); - } - -void engine_get(engine_t * engine, char *string){ - pipex_readln(engine->pipex,string); -} - - +// engine.c + +// includes + +#include +#include +#include +#include + +#include "engine.h" +#include "option.h" +#include "pipex.h" +#include "util.h" + +// variables + +engine_t Engine[1]; + +// functions + +// set_affinity() + +void set_affinity(engine_t *engine, int value){ + pipex_set_affinity(engine->pipex,value); +} + +// engine_set_nice_value() + +void engine_set_nice_value(engine_t *engine, int value){ + pipex_set_priority(engine->pipex,value); +} + +// engine_send_queue() + +void engine_send_queue(engine_t * engine, const char *format, ...) { + char buf[FormatBufferSize]; + CONSTRUCT_ARG_STRING(format,buf); + pipex_write(engine->pipex,buf); +} + +// engine_send() + +void engine_send(engine_t * engine, const char *format, ...) { + char buf[FormatBufferSize]; + CONSTRUCT_ARG_STRING(format,buf); + pipex_writeln(engine->pipex,buf); +} + +// engine_close() + +void engine_close(engine_t * engine){ + char string[StringSize]; + int elapsed_time; + int ret; + int close_timeout=500; + my_log("POLYGLOT Closing engine.\n"); + pipex_send_eof(engine->pipex); + // TODO: Timeout + + elapsed_time=0; + while (!engine_eof(engine) && (elapsed_time=close_timeout){ + my_log("POLYGLOT Waited more than %dms. Moving on.\n",close_timeout); + } + pipex_exit(engine->pipex,200); +} + +// engine_open() + +void engine_open(engine_t * engine){ + int affinity; + pipex_open(engine->pipex, + "Engine", + option_get_string(Option,"EngineDir"), + option_get_string(Option,"EngineCommand")); + if(pipex_active(engine->pipex)){ + //play with affinity (bad idea) + affinity=option_get_int(Option,"Affinity"); + if(affinity!=-1) set_affinity(engine,affinity); //AAA + // set a low priority + if (option_get_bool(Option,"UseNice")){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(engine, option_get_int(Option,"NiceValue")); + } + } + +} + +bool engine_active(engine_t *engine){ + return pipex_active(engine->pipex); +} + +bool engine_eof(engine_t *engine){ + return pipex_eof(engine->pipex); +} + +bool engine_get_non_blocking(engine_t * engine, char *string){ + return pipex_readln_nb(engine->pipex,string); + } + +void engine_get(engine_t * engine, char *string){ + pipex_readln(engine->pipex,string); +} + + diff --git a/engine.h b/engine.h index 70e366b..157e58e 100644 --- a/engine.h +++ b/engine.h @@ -1,36 +1,36 @@ -// engine.h - -#ifndef ENGINE_H -#define ENGINE_H - -// includes - -#include "util.h" -#include "pipex.h" - -// types - -typedef struct { - pipex_t pipex[1]; -} engine_t; - - - -// variables - -extern engine_t Engine[1]; - -// functions - -extern bool engine_is_ok (const engine_t * engine); -extern void engine_open (engine_t * engine); -extern void engine_close (engine_t * engine); -extern bool engine_active (engine_t * engine); -extern bool engine_eof (engine_t * engine); -extern void engine_send (engine_t * engine, const char format[], ...); -extern void engine_send_queue (engine_t * engine, const char format[], ...); -extern bool engine_get_non_blocking(engine_t * engine, char string[]); -extern void engine_get (engine_t * engine, char string[]); -extern void engine_set_nice_value(engine_t * engine, int value); - -#endif // !defined ENGINE_H +// engine.h + +#ifndef ENGINE_H +#define ENGINE_H + +// includes + +#include "util.h" +#include "pipex.h" + +// types + +typedef struct { + pipex_t pipex[1]; +} engine_t; + + + +// variables + +extern engine_t Engine[1]; + +// functions + +extern bool engine_is_ok (const engine_t * engine); +extern void engine_open (engine_t * engine); +extern void engine_close (engine_t * engine); +extern bool engine_active (engine_t * engine); +extern bool engine_eof (engine_t * engine); +extern void engine_send (engine_t * engine, const char format[], ...); +extern void engine_send_queue (engine_t * engine, const char format[], ...); +extern bool engine_get_non_blocking(engine_t * engine, char string[]); +extern void engine_get (engine_t * engine, char string[]); +extern void engine_set_nice_value(engine_t * engine, int value); + +#endif // !defined ENGINE_H diff --git a/epd.c b/epd.c index 4f7ee7b..18f0248 100644 --- a/epd.c +++ b/epd.c @@ -1,447 +1,447 @@ - -// epd.c - -// includes - -#include -#include -#include -#include - -#include "board.h" -#include "engine.h" -#include "epd.h" -#include "fen.h" -#include "line.h" -#include "main.h" -#include "move.h" -#include "move_legal.h" -#include "option.h" -#include "parse.h" -#include "san.h" -#include "uci.h" -#include "util.h" - - -// macros - -#define StringSize 4096 - -// constants - -static const bool UseDebug = FALSE; -static const bool UseTrace = FALSE; - -// variables - -static int MinDepth; -static int MaxDepth; - -static double MaxTime; -static double MinTime; - -static int DepthDelta; - -static int FirstMove; -static int FirstDepth; -static int FirstSelDepth; -static int FirstScore; -static double FirstTime; -static uint64 FirstNodeNb; -static move_t FirstPV[LineSize]; - -static int LastMove; -static int LastDepth; -static int LastSelDepth; -static int LastScore; -static double LastTime; -static uint64 LastNodeNb; -static move_t LastPV[LineSize]; - -static my_timer_t Timer[1]; - -// prototypes - -static void epd_test_file (const char file_name[]); - -static bool is_solution (int move, const board_t * board, const char bm[], const char am[]); -static bool string_contain (const char string[], const char substring[]); - -static bool engine_step (); - -// functions - -// epd_test() - -void epd_test(int argc, char * argv[]) { - - int i; - const char * epd_file; - - epd_file = NULL; - my_string_set(&epd_file,"wac.epd"); - - MinDepth = 8; - MaxDepth = 63; - - MinTime = 1.0; - MaxTime = 5.0; - - DepthDelta = 3; - - for (i = 1; i < argc; i++) { - - if (FALSE) { - - } else if (my_string_equal(argv[i],"epd-test")) { - - // skip - - } else if (my_string_equal(argv[i],"-epd")) { - - i++; - if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); - - my_string_set(&epd_file,argv[i]); - - } else if (my_string_equal(argv[i],"-min-depth")) { - - i++; - if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); - - MinDepth = atoi(argv[i]); - - } else if (my_string_equal(argv[i],"-max-depth")) { - - i++; - if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); - - MaxDepth = atoi(argv[i]); - - } else if (my_string_equal(argv[i],"-min-time")) { - - i++; - if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); - - MinTime = atof(argv[i]); - - } else if (my_string_equal(argv[i],"-max-time")) { - - i++; - if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); - - MaxTime = atof(argv[i]); - - } else if (my_string_equal(argv[i],"-depth-delta")) { - - i++; - if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); - - DepthDelta = atoi(argv[i]); - - } else { - - my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]); - } - } - - if(MinTime>MaxTime){ - MaxTime=MinTime; - } - - epd_test_file(epd_file); -} - -// epd_test_file() - -static void epd_test_file(const char file_name[]) { - - FILE * file; - int hit, tot; - char epd[StringSize]; - char am[StringSize], bm[StringSize], id[StringSize]; - board_t board[1]; - char string[StringSize]; - int move; - char pv_string[StringSize]; - bool correct; - double depth_tot, time_tot, node_tot; - int line=0; - - ASSERT(file_name!=NULL); - - // init - - file = fopen(file_name,"r"); - if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno)); - - hit = 0; - tot = 0; - - depth_tot = 0.0; - time_tot = 0.0; - node_tot = 0.0; - - printf("\nEngineName=%s\n",option_get_string(Option,"EngineName")); - - printf("\n[Search parameters: MaxDepth=%d MaxTime=%.1f DepthDelta=%d MinDepth=%d MinTime=%.1f]\n\n",MaxDepth,MaxTime,DepthDelta,MinDepth,MinTime); - - // loop - - while (my_file_read_line(file,epd,StringSize)) { - line++; - if(my_string_whitespace(epd)) continue; - if (UseTrace) printf("%s\n",epd); - - if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,""); - if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,""); - if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,""); - - if (my_string_empty(am) && my_string_empty(bm)) { - my_fatal("epd_test(): no am or bm field at line %d\n",line); - } - - // init - - uci_send_ucinewgame(Uci); - uci_send_isready_sync(Uci); - - ASSERT(!Uci->searching); - - // position - if (!board_from_fen(board,epd)) ASSERT(FALSE); - if (!board_to_fen(board,string,StringSize)) ASSERT(FALSE); - - engine_send(Engine,"position fen %s",string); - - // search - - my_timer_start(Timer); // also resets - - // which ones of the next two alternatives is best? - engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth); - //engine_send(Engine,"go infinite"); - - // engine data - - board_copy(Uci->board,board); - - uci_clear(Uci); - Uci->searching = TRUE; - Uci->pending_nb++; - - FirstMove = MoveNone; - FirstDepth = 0; - FirstSelDepth = 0; - FirstScore = 0; - FirstTime = 0.0; - FirstNodeNb = 0; - line_clear(FirstPV); - - LastMove = MoveNone; - LastDepth = 0; - LastSelDepth = 0; - LastScore = 0; - LastTime = 0.0; - LastNodeNb = 0; - line_clear(LastPV); - - // parse engine output - - while (!engine_eof(Engine) && engine_step()) { - bool stop=FALSE; - - // stop search? -// printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer)); - if (Uci->depth > MaxDepth){ - my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth); - stop=TRUE; - }else if(my_timer_elapsed_real(Timer) >= MaxTime){ - my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime); - stop=TRUE; - }else if(Uci->depth - FirstDepth >= DepthDelta){ - if(Uci->depth > MinDepth){ - if(Uci->time >= MinTime){ - if(is_solution(FirstMove,board,bm,am)){ - my_log("POLYGLOT Solution found\n",MaxTime); - stop=TRUE; - } - } - } - } - if(stop){ - my_log("POLYGLOT Stopping engine\n"); - engine_send(Engine,"stop"); - break; - } - } - - move = FirstMove; - correct = is_solution(move,board,bm,am); - - if (correct) hit++; - tot++; - - if (correct) { - depth_tot += ((double)FirstDepth); - time_tot += FirstTime; - node_tot += ((double)((sint64)FirstNodeNb)); - } - - printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit); - - if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(FALSE); - printf(" score=%+6.2f pv [D=%2d, T=%7.2fs, N=%6dk] =%s\n",((double)LastScore)/100.0,FirstDepth,FirstTime,(int)FirstNodeNb/1000,pv_string); - } - - printf("\nscore=%d/%d",hit,tot); - - if (hit != 0) { - - depth_tot /= ((double)hit); - time_tot /= ((double)hit); - node_tot /= ((double)hit); - - printf(" [averages on correct positions: depth=%.1f time=%.2f nodes=%.0f]",depth_tot,time_tot,node_tot); - } - - printf("\n"); - - fclose(file); - quit(); -} - -// is_solution() - -static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) { - - char move_string[256]; - bool correct; - - ASSERT(move!=MoveNone); - ASSERT(bm!=NULL); - ASSERT(am!=NULL); - - if (!move_is_legal(move,board)) { - board_disp(board); - move_disp(move,board); - printf("\n\n"); - } - - ASSERT(move_is_legal(move,board)); - - if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE); - - correct = FALSE; - if (!my_string_empty(bm)) { - correct = string_contain(bm,move_string); - } else if (!my_string_empty(am)) { - correct = !string_contain(am,move_string); - } else { - ASSERT(FALSE); - } - - return correct; -} - -// epd_get_op() - -bool epd_get_op(const char record[], const char opcode[], char string[], int size) { - - char op[256]; - int len; - const char *p_start, *p_end; - - ASSERT(record!=NULL); - ASSERT(opcode!=NULL); - ASSERT(string!=NULL); - ASSERT(size>0); - - // find the opcode - - sprintf(op," %s ",opcode); - - p_start = strstr(record,op); - if (p_start == NULL){ - sprintf(op,";%s ",opcode); - p_start = strstr(record,op); - if (p_start == NULL){ - return FALSE; - } - } - - // skip the opcode - - p_start += strlen(op); - - // find the end - p_end = strchr(p_start,';'); - if (p_end == NULL) return FALSE; - - // calculate the length - - len = p_end - p_start; - if (size < len+1) my_fatal("epd_get_op(): size < len+1\n"); - - strncpy(string,p_start,len); - string[len] = '\0'; - - return TRUE; -} - -// string_contain() - -static bool string_contain(const char string[], const char substring[]) { - - char new_string[StringSize], *p; - - strcpy(new_string,string); // HACK - - for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { - if (my_string_equal(p,substring)) return TRUE; - } - - return FALSE; -} - -// engine_step() - -static bool engine_step() { - - char string[StringSize]; - int event; - - engine_get(Engine,string); - event = uci_parse(Uci,string); - - if ((event & EVENT_MOVE) != 0) { - - return FALSE; - } - - if ((event & EVENT_PV) != 0) { - - LastMove = Uci->best_pv[0]; - LastDepth = Uci->best_depth; - LastSelDepth = Uci->best_sel_depth; - LastScore = Uci->best_score; - LastTime = Uci->time; - LastNodeNb = Uci->node_nb; - line_copy(LastPV,Uci->best_pv); - - if (LastMove != FirstMove) { - FirstMove = LastMove; - FirstDepth = LastDepth; - FirstSelDepth = LastSelDepth; - FirstScore = LastScore; - FirstTime = LastTime; - FirstNodeNb = LastNodeNb; - line_copy(FirstPV,LastPV); - } - } - - return TRUE; -} - -// end of epd.cpp - + +// epd.c + +// includes + +#include +#include +#include +#include + +#include "board.h" +#include "engine.h" +#include "epd.h" +#include "fen.h" +#include "line.h" +#include "main.h" +#include "move.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "uci.h" +#include "util.h" + + +// macros + +#define StringSize 4096 + +// constants + +static const bool UseDebug = FALSE; +static const bool UseTrace = FALSE; + +// variables + +static int MinDepth; +static int MaxDepth; + +static double MaxTime; +static double MinTime; + +static int DepthDelta; + +static int FirstMove; +static int FirstDepth; +static int FirstSelDepth; +static int FirstScore; +static double FirstTime; +static uint64 FirstNodeNb; +static move_t FirstPV[LineSize]; + +static int LastMove; +static int LastDepth; +static int LastSelDepth; +static int LastScore; +static double LastTime; +static uint64 LastNodeNb; +static move_t LastPV[LineSize]; + +static my_timer_t Timer[1]; + +// prototypes + +static void epd_test_file (const char file_name[]); + +static bool is_solution (int move, const board_t * board, const char bm[], const char am[]); +static bool string_contain (const char string[], const char substring[]); + +static bool engine_step (); + +// functions + +// epd_test() + +void epd_test(int argc, char * argv[]) { + + int i; + const char * epd_file; + + epd_file = NULL; + my_string_set(&epd_file,"wac.epd"); + + MinDepth = 8; + MaxDepth = 63; + + MinTime = 1.0; + MaxTime = 5.0; + + DepthDelta = 3; + + for (i = 1; i < argc; i++) { + + if (FALSE) { + + } else if (my_string_equal(argv[i],"epd-test")) { + + // skip + + } else if (my_string_equal(argv[i],"-epd")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + my_string_set(&epd_file,argv[i]); + + } else if (my_string_equal(argv[i],"-min-depth")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MinDepth = atoi(argv[i]); + + } else if (my_string_equal(argv[i],"-max-depth")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MaxDepth = atoi(argv[i]); + + } else if (my_string_equal(argv[i],"-min-time")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MinTime = atof(argv[i]); + + } else if (my_string_equal(argv[i],"-max-time")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MaxTime = atof(argv[i]); + + } else if (my_string_equal(argv[i],"-depth-delta")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + DepthDelta = atoi(argv[i]); + + } else { + + my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]); + } + } + + if(MinTime>MaxTime){ + MaxTime=MinTime; + } + + epd_test_file(epd_file); +} + +// epd_test_file() + +static void epd_test_file(const char file_name[]) { + + FILE * file; + int hit, tot; + char epd[StringSize]; + char am[StringSize], bm[StringSize], id[StringSize]; + board_t board[1]; + char string[StringSize]; + int move; + char pv_string[StringSize]; + bool correct; + double depth_tot, time_tot, node_tot; + int line=0; + + ASSERT(file_name!=NULL); + + // init + + file = fopen(file_name,"r"); + if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + + hit = 0; + tot = 0; + + depth_tot = 0.0; + time_tot = 0.0; + node_tot = 0.0; + + printf("\nEngineName=%s\n",option_get_string(Option,"EngineName")); + + printf("\n[Search parameters: MaxDepth=%d MaxTime=%.1f DepthDelta=%d MinDepth=%d MinTime=%.1f]\n\n",MaxDepth,MaxTime,DepthDelta,MinDepth,MinTime); + + // loop + + while (my_file_read_line(file,epd,StringSize)) { + line++; + if(my_string_whitespace(epd)) continue; + if (UseTrace) printf("%s\n",epd); + + if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,""); + if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,""); + if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,""); + + if (my_string_empty(am) && my_string_empty(bm)) { + my_fatal("epd_test(): no am or bm field at line %d\n",line); + } + + // init + + uci_send_ucinewgame(Uci); + uci_send_isready_sync(Uci); + + ASSERT(!Uci->searching); + + // position + if (!board_from_fen(board,epd)) ASSERT(FALSE); + if (!board_to_fen(board,string,StringSize)) ASSERT(FALSE); + + engine_send(Engine,"position fen %s",string); + + // search + + my_timer_start(Timer); // also resets + + // which ones of the next two alternatives is best? + engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth); + //engine_send(Engine,"go infinite"); + + // engine data + + board_copy(Uci->board,board); + + uci_clear(Uci); + Uci->searching = TRUE; + Uci->pending_nb++; + + FirstMove = MoveNone; + FirstDepth = 0; + FirstSelDepth = 0; + FirstScore = 0; + FirstTime = 0.0; + FirstNodeNb = 0; + line_clear(FirstPV); + + LastMove = MoveNone; + LastDepth = 0; + LastSelDepth = 0; + LastScore = 0; + LastTime = 0.0; + LastNodeNb = 0; + line_clear(LastPV); + + // parse engine output + + while (!engine_eof(Engine) && engine_step()) { + bool stop=FALSE; + + // stop search? +// printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer)); + if (Uci->depth > MaxDepth){ + my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth); + stop=TRUE; + }else if(my_timer_elapsed_real(Timer) >= MaxTime){ + my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime); + stop=TRUE; + }else if(Uci->depth - FirstDepth >= DepthDelta){ + if(Uci->depth > MinDepth){ + if(Uci->time >= MinTime){ + if(is_solution(FirstMove,board,bm,am)){ + my_log("POLYGLOT Solution found\n",MaxTime); + stop=TRUE; + } + } + } + } + if(stop){ + my_log("POLYGLOT Stopping engine\n"); + engine_send(Engine,"stop"); + break; + } + } + + move = FirstMove; + correct = is_solution(move,board,bm,am); + + if (correct) hit++; + tot++; + + if (correct) { + depth_tot += ((double)FirstDepth); + time_tot += FirstTime; + node_tot += ((double)((sint64)FirstNodeNb)); + } + + printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit); + + if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(FALSE); + printf(" score=%+6.2f pv [D=%2d, T=%7.2fs, N=%6dk] =%s\n",((double)LastScore)/100.0,FirstDepth,FirstTime,(int)FirstNodeNb/1000,pv_string); + } + + printf("\nscore=%d/%d",hit,tot); + + if (hit != 0) { + + depth_tot /= ((double)hit); + time_tot /= ((double)hit); + node_tot /= ((double)hit); + + printf(" [averages on correct positions: depth=%.1f time=%.2f nodes=%.0f]",depth_tot,time_tot,node_tot); + } + + printf("\n"); + + fclose(file); + quit(); +} + +// is_solution() + +static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) { + + char move_string[256]; + bool correct; + + ASSERT(move!=MoveNone); + ASSERT(bm!=NULL); + ASSERT(am!=NULL); + + if (!move_is_legal(move,board)) { + board_disp(board); + move_disp(move,board); + printf("\n\n"); + } + + ASSERT(move_is_legal(move,board)); + + if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE); + + correct = FALSE; + if (!my_string_empty(bm)) { + correct = string_contain(bm,move_string); + } else if (!my_string_empty(am)) { + correct = !string_contain(am,move_string); + } else { + ASSERT(FALSE); + } + + return correct; +} + +// epd_get_op() + +bool epd_get_op(const char record[], const char opcode[], char string[], int size) { + + char op[256]; + int len; + const char *p_start, *p_end; + + ASSERT(record!=NULL); + ASSERT(opcode!=NULL); + ASSERT(string!=NULL); + ASSERT(size>0); + + // find the opcode + + sprintf(op," %s ",opcode); + + p_start = strstr(record,op); + if (p_start == NULL){ + sprintf(op,";%s ",opcode); + p_start = strstr(record,op); + if (p_start == NULL){ + return FALSE; + } + } + + // skip the opcode + + p_start += strlen(op); + + // find the end + p_end = strchr(p_start,';'); + if (p_end == NULL) return FALSE; + + // calculate the length + + len = p_end - p_start; + if (size < len+1) my_fatal("epd_get_op(): size < len+1\n"); + + strncpy(string,p_start,len); + string[len] = '\0'; + + return TRUE; +} + +// string_contain() + +static bool string_contain(const char string[], const char substring[]) { + + char new_string[StringSize], *p; + + strcpy(new_string,string); // HACK + + for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { + if (my_string_equal(p,substring)) return TRUE; + } + + return FALSE; +} + +// engine_step() + +static bool engine_step() { + + char string[StringSize]; + int event; + + engine_get(Engine,string); + event = uci_parse(Uci,string); + + if ((event & EVENT_MOVE) != 0) { + + return FALSE; + } + + if ((event & EVENT_PV) != 0) { + + LastMove = Uci->best_pv[0]; + LastDepth = Uci->best_depth; + LastSelDepth = Uci->best_sel_depth; + LastScore = Uci->best_score; + LastTime = Uci->time; + LastNodeNb = Uci->node_nb; + line_copy(LastPV,Uci->best_pv); + + if (LastMove != FirstMove) { + FirstMove = LastMove; + FirstDepth = LastDepth; + FirstSelDepth = LastSelDepth; + FirstScore = LastScore; + FirstTime = LastTime; + FirstNodeNb = LastNodeNb; + line_copy(FirstPV,LastPV); + } + } + + return TRUE; +} + +// end of epd.cpp + diff --git a/epd.h b/epd.h index 896879d..e20cae5 100644 --- a/epd.h +++ b/epd.h @@ -1,20 +1,20 @@ - -// epd.h - -#ifndef EPD_H -#define EPD_H - -// includes - -#include "util.h" - -// functions - -extern void epd_test (int argc, char * argv[]); - -extern bool epd_get_op (const char record[], const char opcode[], char string[], int size); - -#endif // !defined EPD_H - -// end of epd.h - + +// epd.h + +#ifndef EPD_H +#define EPD_H + +// includes + +#include "util.h" + +// functions + +extern void epd_test (int argc, char * argv[]); + +extern bool epd_get_op (const char record[], const char opcode[], char string[], int size); + +#endif // !defined EPD_H + +// end of epd.h + diff --git a/fen.c b/fen.c index 180bdf3..cfab964 100644 --- a/fen.c +++ b/fen.c @@ -1,392 +1,392 @@ - -// fen.c - -// includes - -#include -#include -#include - -#include "board.h" -#include "colour.h" -#include "fen.h" -#include "option.h" -#include "piece.h" -#include "square.h" -#include "util.h" - -// "constants" - -// const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1"; -const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; - -// variables - -static const bool Strict = FALSE; - -// macros - -#define skip_white_space() \ - c=string[pos];\ - if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \ - while(c==' ' || c=='\t') c=string[++pos]; - - -// functions - -// board_from_fen() - -bool board_from_fen(board_t * board, const char string[]) { - - int pos; - int file, rank, sq; - int c; - int i, len; - int piece; - int king_pos[ColourNb]; - - ASSERT(board!=NULL); - ASSERT(string!=NULL); - - board_clear(board); - - king_pos[White] = SquareNone; - king_pos[Black] = SquareNone; - - pos = 0; - c = string[pos]; - - // piece placement - - for (rank = 7; rank >= 0; rank--) { - - for (file = 0; file < 8;) { - - sq = square_make(file,rank); - - if (c >= '1' && c <= '8') { // empty square(s) - - len = c - '0'; - if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - - for (i = 0; i < len; i++) { - board->square[sq++] = Empty; - file++; - } - - } else { // piece - - piece = piece_from_char(c); - if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - - if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq; - - board->square[sq++] = piece; - file++; - } - - c = string[++pos]; - } - - if (rank > 0) { - if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - c = string[++pos]; - } - } - - // active colour - - skip_white_space(); - - switch (c) { - case 'w': - board->turn = White; - break; - case 'b': - board->turn = Black; - break; - default: - my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - break; - } - - c = string[++pos]; - - // castling - - skip_white_space(); - - board->castle[White][SideH] = SquareNone; - board->castle[White][SideA] = SquareNone; - board->castle[Black][SideH] = SquareNone; - board->castle[Black][SideA] = SquareNone; - - if (c == '-') { // no castling rights - - c = string[++pos]; - - } else { - - // TODO: filter out illegal rights - - do { - - if (FALSE) { - - } else if (c == 'K') { - - for (sq = H1; sq > king_pos[White]; sq--) { - if (board->square[sq] == WhiteRook256) { - board->castle[White][SideH] = sq; - break; - } - } - - } else if (c == 'Q') { - - for (sq = A1; sq < king_pos[White]; sq++) { - if (board->square[sq] == WhiteRook256) { - board->castle[White][SideA] = sq; - break; - } - } - - } else if (c == 'k') { - - for (sq = H8; sq > king_pos[Black]; sq--) { - if (board->square[sq] == BlackRook256) { - board->castle[Black][SideH] = sq; - break; - } - } - - } else if (c == 'q') { - - for (sq = A8; sq < king_pos[Black]; sq++) { - if (board->square[sq] == BlackRook256) { - board->castle[Black][SideA] = sq; - break; - } - } - - } else if (c >= 'A' && c <= 'H') { - - // white castling right - - sq = square_make(file_from_char(tolower(c)),Rank1); - - if (sq > king_pos[White]) { // h side - board->castle[White][SideH] = sq; - } else { // a side - board->castle[White][SideA] = sq; - } - - } else if (c >= 'a' && c <= 'h') { - - // black castling right - - sq = square_make(file_from_char(tolower(c)),Rank8); - - if (sq > king_pos[Black]) { // h side - board->castle[Black][SideH] = sq; - } else { // a side - board->castle[Black][SideA] = sq; - } - - } else { - - my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - } - - c = string[++pos]; - - } while (c != ' '); - } - - // en-passant - - skip_white_space(); - - if (c == '-') { // no en-passant - - sq = SquareNone; - c = string[++pos]; - - } else { - - if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - file = file_from_char(c); - c = string[++pos]; - - if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - rank = rank_from_char(c); - c = string[++pos]; - - sq = square_make(file,rank); - } - - board->ep_square = sq; - - // halfmove clock - - board->ply_nb = 0; - board->move_nb = 0; // HACK, in case of broken syntax - - if (c != ' ') { - if (!Strict) goto update; - my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - } - c = string[++pos]; - - if (!isdigit(c)) { - if (!Strict) goto update; - my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - } - - board->ply_nb = atoi(&string[pos]); - do c = string[++pos]; while (isdigit(c)); - - // fullmove number - - board->move_nb = 0; - - if (c != ' ') { - if (!Strict) goto update; - my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - } - c = string[++pos]; - - if (!isdigit(c)) { - if (!Strict) goto update; - my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); - } - - board->move_nb = atoi(&string[pos]) - 1; - do c = string[++pos]; while (isdigit(c)); - - // board update - -update: - board_init_list(board); - - return TRUE; -} - -// board_to_fen() - -bool board_to_fen(const board_t * board, char string[], int size) { - - int pos; - int file, rank; - int sq, piece; - int c; - int len; - int old_pos; - - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=92); - - // init - - if (size < 92) return FALSE; - - pos = 0; - - // piece placement - - for (rank = 7; rank >= 0; rank--) { - - for (file = 0; file < 8;) { - - sq = square_make(file,rank); - piece = board->square[sq]; - ASSERT(piece==Empty||piece_is_ok(piece)); - - if (piece == Empty) { - - len = 0; - for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) { - len++; - } - - ASSERT(len>=1&&len<=8); - c = '0' + len; - - } else { - - c = piece_to_char(piece); - file++; - } - - string[pos++] = c; - } - - string[pos++] = '/'; - } - - string[pos-1] = ' '; // HACK: remove the last '/' - - // active colour - - string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b'; - string[pos++] = ' '; - - // castling - - old_pos = pos; - - if (option_get_bool(Option,"Chess960")) { - - // FEN-960 - - if (board->castle[White][SideH] != SquareNone) { - string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH]))); - } - - if (board->castle[White][SideA] != SquareNone) { - string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA]))); - } - - if (board->castle[Black][SideH] != SquareNone) { - string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH]))); - } - - if (board->castle[Black][SideA] != SquareNone) { - string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA]))); - } - - } else { - - // FEN - - if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K'; - if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q'; - if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k'; - if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q'; - } - - if (pos == old_pos) string[pos++] = '-'; - - string[pos++] = ' '; - - // en-passant - - if (board->ep_square == SquareNone) { - string[pos++] = '-'; - } else { - if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE; - pos += 2; - } - - string[pos++] = ' '; - - // halfmove clock and fullmove number - - sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1); - - return TRUE; -} - -// end of fen.cpp - + +// fen.c + +// includes + +#include +#include +#include + +#include "board.h" +#include "colour.h" +#include "fen.h" +#include "option.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// "constants" + +// const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1"; +const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + +// variables + +static const bool Strict = FALSE; + +// macros + +#define skip_white_space() \ + c=string[pos];\ + if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \ + while(c==' ' || c=='\t') c=string[++pos]; + + +// functions + +// board_from_fen() + +bool board_from_fen(board_t * board, const char string[]) { + + int pos; + int file, rank, sq; + int c; + int i, len; + int piece; + int king_pos[ColourNb]; + + ASSERT(board!=NULL); + ASSERT(string!=NULL); + + board_clear(board); + + king_pos[White] = SquareNone; + king_pos[Black] = SquareNone; + + pos = 0; + c = string[pos]; + + // piece placement + + for (rank = 7; rank >= 0; rank--) { + + for (file = 0; file < 8;) { + + sq = square_make(file,rank); + + if (c >= '1' && c <= '8') { // empty square(s) + + len = c - '0'; + if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + + for (i = 0; i < len; i++) { + board->square[sq++] = Empty; + file++; + } + + } else { // piece + + piece = piece_from_char(c); + if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + + if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq; + + board->square[sq++] = piece; + file++; + } + + c = string[++pos]; + } + + if (rank > 0) { + if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + c = string[++pos]; + } + } + + // active colour + + skip_white_space(); + + switch (c) { + case 'w': + board->turn = White; + break; + case 'b': + board->turn = Black; + break; + default: + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + break; + } + + c = string[++pos]; + + // castling + + skip_white_space(); + + board->castle[White][SideH] = SquareNone; + board->castle[White][SideA] = SquareNone; + board->castle[Black][SideH] = SquareNone; + board->castle[Black][SideA] = SquareNone; + + if (c == '-') { // no castling rights + + c = string[++pos]; + + } else { + + // TODO: filter out illegal rights + + do { + + if (FALSE) { + + } else if (c == 'K') { + + for (sq = H1; sq > king_pos[White]; sq--) { + if (board->square[sq] == WhiteRook256) { + board->castle[White][SideH] = sq; + break; + } + } + + } else if (c == 'Q') { + + for (sq = A1; sq < king_pos[White]; sq++) { + if (board->square[sq] == WhiteRook256) { + board->castle[White][SideA] = sq; + break; + } + } + + } else if (c == 'k') { + + for (sq = H8; sq > king_pos[Black]; sq--) { + if (board->square[sq] == BlackRook256) { + board->castle[Black][SideH] = sq; + break; + } + } + + } else if (c == 'q') { + + for (sq = A8; sq < king_pos[Black]; sq++) { + if (board->square[sq] == BlackRook256) { + board->castle[Black][SideA] = sq; + break; + } + } + + } else if (c >= 'A' && c <= 'H') { + + // white castling right + + sq = square_make(file_from_char(tolower(c)),Rank1); + + if (sq > king_pos[White]) { // h side + board->castle[White][SideH] = sq; + } else { // a side + board->castle[White][SideA] = sq; + } + + } else if (c >= 'a' && c <= 'h') { + + // black castling right + + sq = square_make(file_from_char(tolower(c)),Rank8); + + if (sq > king_pos[Black]) { // h side + board->castle[Black][SideH] = sq; + } else { // a side + board->castle[Black][SideA] = sq; + } + + } else { + + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + + c = string[++pos]; + + } while (c != ' '); + } + + // en-passant + + skip_white_space(); + + if (c == '-') { // no en-passant + + sq = SquareNone; + c = string[++pos]; + + } else { + + if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + file = file_from_char(c); + c = string[++pos]; + + if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + rank = rank_from_char(c); + c = string[++pos]; + + sq = square_make(file,rank); + } + + board->ep_square = sq; + + // halfmove clock + + board->ply_nb = 0; + board->move_nb = 0; // HACK, in case of broken syntax + + if (c != ' ') { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + c = string[++pos]; + + if (!isdigit(c)) { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + + board->ply_nb = atoi(&string[pos]); + do c = string[++pos]; while (isdigit(c)); + + // fullmove number + + board->move_nb = 0; + + if (c != ' ') { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + c = string[++pos]; + + if (!isdigit(c)) { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + + board->move_nb = atoi(&string[pos]) - 1; + do c = string[++pos]; while (isdigit(c)); + + // board update + +update: + board_init_list(board); + + return TRUE; +} + +// board_to_fen() + +bool board_to_fen(const board_t * board, char string[], int size) { + + int pos; + int file, rank; + int sq, piece; + int c; + int len; + int old_pos; + + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=92); + + // init + + if (size < 92) return FALSE; + + pos = 0; + + // piece placement + + for (rank = 7; rank >= 0; rank--) { + + for (file = 0; file < 8;) { + + sq = square_make(file,rank); + piece = board->square[sq]; + ASSERT(piece==Empty||piece_is_ok(piece)); + + if (piece == Empty) { + + len = 0; + for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) { + len++; + } + + ASSERT(len>=1&&len<=8); + c = '0' + len; + + } else { + + c = piece_to_char(piece); + file++; + } + + string[pos++] = c; + } + + string[pos++] = '/'; + } + + string[pos-1] = ' '; // HACK: remove the last '/' + + // active colour + + string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b'; + string[pos++] = ' '; + + // castling + + old_pos = pos; + + if (option_get_bool(Option,"Chess960")) { + + // FEN-960 + + if (board->castle[White][SideH] != SquareNone) { + string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH]))); + } + + if (board->castle[White][SideA] != SquareNone) { + string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA]))); + } + + if (board->castle[Black][SideH] != SquareNone) { + string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH]))); + } + + if (board->castle[Black][SideA] != SquareNone) { + string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA]))); + } + + } else { + + // FEN + + if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K'; + if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q'; + if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k'; + if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q'; + } + + if (pos == old_pos) string[pos++] = '-'; + + string[pos++] = ' '; + + // en-passant + + if (board->ep_square == SquareNone) { + string[pos++] = '-'; + } else { + if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE; + pos += 2; + } + + string[pos++] = ' '; + + // halfmove clock and fullmove number + + sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1); + + return TRUE; +} + +// end of fen.cpp + diff --git a/fen.h b/fen.h index fe5183e..0b9e21b 100644 --- a/fen.h +++ b/fen.h @@ -1,24 +1,24 @@ - -// fen.h - -#ifndef FEN_H -#define FEN_H - -// includes - -#include "board.h" -#include "util.h" - -// "constants" - -extern const char * StartFen; - -// functions - -extern bool board_from_fen (board_t * board, const char string[]); -extern bool board_to_fen (const board_t * board, char string[], int size); - -#endif // !defined FEN_H - -// end of fen.h - + +// fen.h + +#ifndef FEN_H +#define FEN_H + +// includes + +#include "board.h" +#include "util.h" + +// "constants" + +extern const char * StartFen; + +// functions + +extern bool board_from_fen (board_t * board, const char string[]); +extern bool board_to_fen (const board_t * board, char string[], int size); + +#endif // !defined FEN_H + +// end of fen.h + diff --git a/game.c b/game.c index 199d344..d28031d 100644 --- a/game.c +++ b/game.c @@ -1,361 +1,361 @@ - -// game.c - -// includes - -#include "attack.h" -#include "board.h" -#include "fen.h" -#include "game.h" -#include "list.h" -#include "move.h" -#include "move_do.h" -#include "move_legal.h" -#include "piece.h" -#include "square.h" -#include "util.h" - -// constants - -static const bool UseSlowDebug = FALSE; - -// variables - -game_t Game[1]; - -// prototypes - -static void game_update (game_t * game); -static int game_comp_status (const game_t * game); - -// functions - -// game_is_ok() - -bool game_is_ok(const game_t * game) { - - board_t board[1]; - int pos, move; - - if (game == NULL) return FALSE; - - if (game->size < 0 || game->size > GameSize) return FALSE; - if (game->pos < 0 || game->pos > game->size) return FALSE; - - // optional heavy DEBUG mode - - if (!UseSlowDebug) return TRUE; - - if (!board_is_ok(game->start_board)) return FALSE; - - board_copy(board,game->start_board); - - for (pos = 0; pos <= game->size; pos++) { - - if (pos == game->pos) { - if (!board_equal(game->board,board)) return FALSE; - } - - if (pos >= game->size) break; - - if (game->key[pos] != board->key) return FALSE; - - move = game->move[pos]; - //if (!move_is_legal(move,board)); //huh?? - if (!move_is_legal(move,board)) return FALSE; - - move_do(board,move); - } - - if (game->status != game_comp_status(game)) return FALSE; - - return TRUE; -} - -// game_clear() - -void game_clear(game_t * game) { - - ASSERT(game!=NULL); - - game_init(game,StartFen); -} - -// game_init() - -bool game_init(game_t * game, const char fen[]) { - - ASSERT(game!=NULL); - ASSERT(fen!=NULL); - - if (!board_from_fen(game->start_board,fen)) return FALSE; - - game->size = 0; - - board_copy(game->board,game->start_board); - game->pos = 0; - - game_update(game); - - return TRUE; -} - -// game_status() - -int game_status(const game_t * game) { - - ASSERT(game!=NULL); - - return game->status; -} - -// game_size() - -int game_size(const game_t * game) { - - ASSERT(game!=NULL); - - return game->size; -} - -// game_pos() - -int game_pos(const game_t * game) { - - ASSERT(game!=NULL); - - return game->pos; -} - -// game_move() - -int game_move(const game_t * game, int pos) { - - ASSERT(game!=NULL); - ASSERT(pos>=0&&pospos); - - return game->move[pos]; -} - -// game_get_board() - -void game_get_board(const game_t * game, board_t * board) { - game_get_board_ex(game, board, -1); -} - -// game_get_board_ex() - -void game_get_board_ex(const game_t * game, board_t * board, int pos) { - - int start; - int i; - - ASSERT(game!=NULL); - ASSERT(board!=NULL); - ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK - - if (pos < 0) pos = game->pos; - - if (pos >= game->pos) { // forward from current position - start = game->pos; - board_copy(board,game->board); - } else { // backward => replay the whole game - start = 0; - board_copy(board,game->start_board); - } - - for (i = start; i < pos; i++) move_do(board,game->move[i]); -} - -// game_turn() - -int game_turn(const game_t * game) { - - ASSERT(game!=NULL); - - return game->board->turn; -} - -// game_move_nb() - -int game_move_nb(const game_t * game) { - - ASSERT(game!=NULL); - - return game->board->move_nb; -} - -// game_add_move() - -void game_add_move(game_t * game, int move) { - - ASSERT(game!=NULL); - ASSERT(move_is_ok(move)); - - ASSERT(move_is_legal(move,game->board)); - - if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n"); - - game->move[game->pos] = move; - game->key[game->pos] = game->board->key; - - move_do(game->board,move); - game->pos++; - - game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update() - - game_update(game); -} - -// game_rem_move() - -void game_rem_move(game_t * game) { - - ASSERT(game!=NULL); - - game_goto(game,game->pos-1); - - game->size = game->pos; // truncate game -} - -// game_goto() - -void game_goto(game_t * game, int pos) { - - int i; - - ASSERT(game!=NULL); - ASSERT(pos>=0&&pos<=game->size); - - if (pos < game->pos) { // going backward => replay the whole game - board_copy(game->board,game->start_board); - game->pos = 0; - } - - for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]); - ASSERT(i==pos); - - game->pos = pos; - - game_update(game); -} - -// game_disp() - -void game_disp(const game_t * game) { - - board_t board[1]; - int i, move; - - ASSERT(game_is_ok(game)); - - board_copy(board,game->start_board); - - board_disp(board); - - for (i = 0; i < game->pos; i++) { - - move = game->move[i]; - move_disp(move,board); - - move_do(board,move); - } - - my_log("POLYGLOT\n"); - - board_disp(board); -} - -// game_update() - -static void game_update(game_t * game) { - - ASSERT(game!=NULL); - - game->status = game_comp_status(game); - - ASSERT(game_is_ok(game)); -} - -// game_comp_status() - -static int game_comp_status(const game_t * game) { - - int i, n; - int wb, bb; - const board_t * board; - uint64 key; - int start; - - ASSERT(game!=NULL); - - // init - - board = game->board; - - // mate and stalemate - - if (!board_can_play(board)) { - if (FALSE) { - } else if (is_in_check(board,Black)) { // HACK - return WHITE_MATES; - } else if (is_in_check(board,White)) { // HACK - return BLACK_MATES; - } else { - return STALEMATE; - } - } - - // insufficient material - - if (board->number[WhitePawn12] == 0 - && board->number[BlackPawn12] == 0 - && board->number[WhiteQueen12] == 0 - && board->number[BlackQueen12] == 0 - && board->number[WhiteRook12] == 0 - && board->number[BlackRook12] == 0) { - - if (board->number[WhiteBishop12] - + board->number[BlackBishop12] - + board->number[WhiteKnight12] - + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK - - return DRAW_MATERIAL; - - } else if (board->number[WhiteBishop12] == 1 - && board->number[BlackBishop12] == 1 - && board->number[WhiteKnight12] == 0 - && board->number[BlackKnight12] == 0) { - - wb = board->list[White][1]; // HACK - bb = board->list[Black][1]; // HACK - - if (square_colour(wb) == square_colour(bb)) { // KBKB - return DRAW_MATERIAL; - } - } - } - - // 50-move rule - - if (board->ply_nb >= 100) return DRAW_FIFTY; - - // position repetition - - key = board->key; - n = 0; - - start = game->pos - board->ply_nb; - if (start < 0) start = 0; - - for (i = game->pos-4; i >= start; i -= 2) { - if (game->key[i] == key) { - if (++n == 2) return DRAW_REPETITION; - } - } - - return PLAYING; -} - -// end of game.cpp - + +// game.c + +// includes + +#include "attack.h" +#include "board.h" +#include "fen.h" +#include "game.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// constants + +static const bool UseSlowDebug = FALSE; + +// variables + +game_t Game[1]; + +// prototypes + +static void game_update (game_t * game); +static int game_comp_status (const game_t * game); + +// functions + +// game_is_ok() + +bool game_is_ok(const game_t * game) { + + board_t board[1]; + int pos, move; + + if (game == NULL) return FALSE; + + if (game->size < 0 || game->size > GameSize) return FALSE; + if (game->pos < 0 || game->pos > game->size) return FALSE; + + // optional heavy DEBUG mode + + if (!UseSlowDebug) return TRUE; + + if (!board_is_ok(game->start_board)) return FALSE; + + board_copy(board,game->start_board); + + for (pos = 0; pos <= game->size; pos++) { + + if (pos == game->pos) { + if (!board_equal(game->board,board)) return FALSE; + } + + if (pos >= game->size) break; + + if (game->key[pos] != board->key) return FALSE; + + move = game->move[pos]; + //if (!move_is_legal(move,board)); //huh?? + if (!move_is_legal(move,board)) return FALSE; + + move_do(board,move); + } + + if (game->status != game_comp_status(game)) return FALSE; + + return TRUE; +} + +// game_clear() + +void game_clear(game_t * game) { + + ASSERT(game!=NULL); + + game_init(game,StartFen); +} + +// game_init() + +bool game_init(game_t * game, const char fen[]) { + + ASSERT(game!=NULL); + ASSERT(fen!=NULL); + + if (!board_from_fen(game->start_board,fen)) return FALSE; + + game->size = 0; + + board_copy(game->board,game->start_board); + game->pos = 0; + + game_update(game); + + return TRUE; +} + +// game_status() + +int game_status(const game_t * game) { + + ASSERT(game!=NULL); + + return game->status; +} + +// game_size() + +int game_size(const game_t * game) { + + ASSERT(game!=NULL); + + return game->size; +} + +// game_pos() + +int game_pos(const game_t * game) { + + ASSERT(game!=NULL); + + return game->pos; +} + +// game_move() + +int game_move(const game_t * game, int pos) { + + ASSERT(game!=NULL); + ASSERT(pos>=0&&pospos); + + return game->move[pos]; +} + +// game_get_board() + +void game_get_board(const game_t * game, board_t * board) { + game_get_board_ex(game, board, -1); +} + +// game_get_board_ex() + +void game_get_board_ex(const game_t * game, board_t * board, int pos) { + + int start; + int i; + + ASSERT(game!=NULL); + ASSERT(board!=NULL); + ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK + + if (pos < 0) pos = game->pos; + + if (pos >= game->pos) { // forward from current position + start = game->pos; + board_copy(board,game->board); + } else { // backward => replay the whole game + start = 0; + board_copy(board,game->start_board); + } + + for (i = start; i < pos; i++) move_do(board,game->move[i]); +} + +// game_turn() + +int game_turn(const game_t * game) { + + ASSERT(game!=NULL); + + return game->board->turn; +} + +// game_move_nb() + +int game_move_nb(const game_t * game) { + + ASSERT(game!=NULL); + + return game->board->move_nb; +} + +// game_add_move() + +void game_add_move(game_t * game, int move) { + + ASSERT(game!=NULL); + ASSERT(move_is_ok(move)); + + ASSERT(move_is_legal(move,game->board)); + + if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n"); + + game->move[game->pos] = move; + game->key[game->pos] = game->board->key; + + move_do(game->board,move); + game->pos++; + + game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update() + + game_update(game); +} + +// game_rem_move() + +void game_rem_move(game_t * game) { + + ASSERT(game!=NULL); + + game_goto(game,game->pos-1); + + game->size = game->pos; // truncate game +} + +// game_goto() + +void game_goto(game_t * game, int pos) { + + int i; + + ASSERT(game!=NULL); + ASSERT(pos>=0&&pos<=game->size); + + if (pos < game->pos) { // going backward => replay the whole game + board_copy(game->board,game->start_board); + game->pos = 0; + } + + for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]); + ASSERT(i==pos); + + game->pos = pos; + + game_update(game); +} + +// game_disp() + +void game_disp(const game_t * game) { + + board_t board[1]; + int i, move; + + ASSERT(game_is_ok(game)); + + board_copy(board,game->start_board); + + board_disp(board); + + for (i = 0; i < game->pos; i++) { + + move = game->move[i]; + move_disp(move,board); + + move_do(board,move); + } + + my_log("POLYGLOT\n"); + + board_disp(board); +} + +// game_update() + +static void game_update(game_t * game) { + + ASSERT(game!=NULL); + + game->status = game_comp_status(game); + + ASSERT(game_is_ok(game)); +} + +// game_comp_status() + +static int game_comp_status(const game_t * game) { + + int i, n; + int wb, bb; + const board_t * board; + uint64 key; + int start; + + ASSERT(game!=NULL); + + // init + + board = game->board; + + // mate and stalemate + + if (!board_can_play(board)) { + if (FALSE) { + } else if (is_in_check(board,Black)) { // HACK + return WHITE_MATES; + } else if (is_in_check(board,White)) { // HACK + return BLACK_MATES; + } else { + return STALEMATE; + } + } + + // insufficient material + + if (board->number[WhitePawn12] == 0 + && board->number[BlackPawn12] == 0 + && board->number[WhiteQueen12] == 0 + && board->number[BlackQueen12] == 0 + && board->number[WhiteRook12] == 0 + && board->number[BlackRook12] == 0) { + + if (board->number[WhiteBishop12] + + board->number[BlackBishop12] + + board->number[WhiteKnight12] + + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK + + return DRAW_MATERIAL; + + } else if (board->number[WhiteBishop12] == 1 + && board->number[BlackBishop12] == 1 + && board->number[WhiteKnight12] == 0 + && board->number[BlackKnight12] == 0) { + + wb = board->list[White][1]; // HACK + bb = board->list[Black][1]; // HACK + + if (square_colour(wb) == square_colour(bb)) { // KBKB + return DRAW_MATERIAL; + } + } + } + + // 50-move rule + + if (board->ply_nb >= 100) return DRAW_FIFTY; + + // position repetition + + key = board->key; + n = 0; + + start = game->pos - board->ply_nb; + if (start < 0) start = 0; + + for (i = game->pos-4; i >= start; i -= 2) { + if (game->key[i] == key) { + if (++n == 2) return DRAW_REPETITION; + } + } + + return PLAYING; +} + +// end of game.cpp + diff --git a/game.h b/game.h index e0fce79..5b26bfd 100644 --- a/game.h +++ b/game.h @@ -1,73 +1,73 @@ - -// game.h - -#ifndef GAME_H -#define GAME_H - -// includes - -#include "board.h" -#include "move.h" -#include "util.h" - -// defines - -#define GameSize 4096 - -// types - -typedef enum { - PLAYING, - WHITE_MATES, - BLACK_MATES, - STALEMATE, - DRAW_MATERIAL, - DRAW_FIFTY, - DRAW_REPETITION -} status_t; - -// types - -typedef struct { - board_t start_board[1]; - board_t board[1]; - sint16 size; - sint16 pos; - sint8 status; - move_t move[GameSize]; - uint64 key[GameSize]; -} game_t; - -// variables - -extern game_t Game[1]; - -// functions - -extern bool game_is_ok (const game_t * game); - -extern void game_clear (game_t * game); -extern bool game_init (game_t * game, const char fen[]); - -extern int game_status (const game_t * game); - -extern int game_size (const game_t * game); -extern int game_pos (const game_t * game); -extern int game_move (const game_t * game, int pos); - -extern void game_get_board (const game_t * game, board_t * board); -extern void game_get_board_ex (const game_t * game, board_t * board, int pos); -extern int game_turn (const game_t * game); -extern int game_move_nb (const game_t * game); - -extern void game_add_move (game_t * game, int move); -extern void game_rem_move (game_t * game); - -extern void game_goto (game_t * game, int pos); - -extern void game_disp (const game_t * game); - -#endif // !defined GAME_H - -// end of game.h - + +// game.h + +#ifndef GAME_H +#define GAME_H + +// includes + +#include "board.h" +#include "move.h" +#include "util.h" + +// defines + +#define GameSize 4096 + +// types + +typedef enum { + PLAYING, + WHITE_MATES, + BLACK_MATES, + STALEMATE, + DRAW_MATERIAL, + DRAW_FIFTY, + DRAW_REPETITION +} status_t; + +// types + +typedef struct { + board_t start_board[1]; + board_t board[1]; + sint16 size; + sint16 pos; + sint8 status; + move_t move[GameSize]; + uint64 key[GameSize]; +} game_t; + +// variables + +extern game_t Game[1]; + +// functions + +extern bool game_is_ok (const game_t * game); + +extern void game_clear (game_t * game); +extern bool game_init (game_t * game, const char fen[]); + +extern int game_status (const game_t * game); + +extern int game_size (const game_t * game); +extern int game_pos (const game_t * game); +extern int game_move (const game_t * game, int pos); + +extern void game_get_board (const game_t * game, board_t * board); +extern void game_get_board_ex (const game_t * game, board_t * board, int pos); +extern int game_turn (const game_t * game); +extern int game_move_nb (const game_t * game); + +extern void game_add_move (game_t * game, int move); +extern void game_rem_move (game_t * game); + +extern void game_goto (game_t * game, int pos); + +extern void game_disp (const game_t * game); + +#endif // !defined GAME_H + +// end of game.h + diff --git a/gui.c b/gui.c index 44abc37..9a0d102 100644 --- a/gui.c +++ b/gui.c @@ -8,10 +8,6 @@ #include "gui.h" #include "main.h" -// constants - -static const int StringSize = 4096; - // variables gui_t GUI[1]; diff --git a/hash.c b/hash.c index 4baa0aa..4205130 100644 --- a/hash.c +++ b/hash.c @@ -1,128 +1,128 @@ - -// hash.c - -// includes - -#include "board.h" -#include "hash.h" -#include "piece.h" -#include "random.h" -#include "square.h" -#include "util.h" - -// variables - -static uint64 Castle64[16]; - -// prototypes - -static uint64 hash_castle_key_debug (int flags); - -// functions - -// hash_init() - -void hash_init() { - - int i; - - for (i = 0; i < 16; i++) Castle64[i] = hash_castle_key_debug(i); -} - -// hash_key() - -uint64 hash_key(const board_t * board) { - - uint64 key; - int colour; - const uint8 * ptr; - int sq, piece; - - ASSERT(board_is_ok(board)); - - // init - - key = 0; - - // pieces - - for (colour = 1; colour <= 2; colour++) { // HACK - for (ptr = board->list[colour]; (sq=*ptr) != SquareNone; ptr++) { - piece = board->square[sq]; - key ^= hash_piece_key(piece,sq); - } - } - - // castle flags - - key ^= hash_castle_key(board_flags(board)); - - // en-passant square - - sq = board->ep_square; - if (sq != SquareNone) key ^= hash_ep_key(sq); - - // turn - - key ^= hash_turn_key(board->turn); - - return key; -} - -// hash_piece_key() - -uint64 hash_piece_key(int piece, int square) { - - ASSERT(piece_is_ok(piece)); - ASSERT(square_is_ok(square)); - - return random_64(RandomPiece+piece_to_12(piece)*64+square_to_64(square)); -} - -// hash_castle_key() - -uint64 hash_castle_key(int flags) { - - ASSERT((flags&~0xF)==0); - - return Castle64[flags]; -} - -// hash_castle_key_debug() - -static uint64 hash_castle_key_debug(int flags) { - - uint64 key; - int i; - - ASSERT((flags&~0xF)==0); - - key = 0; - - for (i = 0; i < 4; i++) { - if ((flags & (1<list[colour]; (sq=*ptr) != SquareNone; ptr++) { + piece = board->square[sq]; + key ^= hash_piece_key(piece,sq); + } + } + + // castle flags + + key ^= hash_castle_key(board_flags(board)); + + // en-passant square + + sq = board->ep_square; + if (sq != SquareNone) key ^= hash_ep_key(sq); + + // turn + + key ^= hash_turn_key(board->turn); + + return key; +} + +// hash_piece_key() + +uint64 hash_piece_key(int piece, int square) { + + ASSERT(piece_is_ok(piece)); + ASSERT(square_is_ok(square)); + + return random_64(RandomPiece+piece_to_12(piece)*64+square_to_64(square)); +} + +// hash_castle_key() + +uint64 hash_castle_key(int flags) { + + ASSERT((flags&~0xF)==0); + + return Castle64[flags]; +} + +// hash_castle_key_debug() + +static uint64 hash_castle_key_debug(int flags) { + + uint64 key; + int i; + + ASSERT((flags&~0xF)==0); + + key = 0; + + for (i = 0; i < 4; i++) { + if ((flags & (1< - -#include "board.h" -#include "line.h" -#include "move.h" -#include "move_do.h" -#include "move_legal.h" -#include "san.h" -#include "util.h" - -// constants - -static const bool Strict = FALSE; // FALSE -static const bool UseDebug = FALSE; // FALSE - -#define StringSize ((int)1024) - -// functions - -// line_is_ok() - -bool line_is_ok(const move_t line[]) { - - int move; - - if (line == NULL) return FALSE; - - while ((move = *line++) != MoveNone) { - if (!move_is_ok(move)) return FALSE; - } - - return TRUE; -} - -// line_clear() - -void line_clear(move_t line[]) { - - ASSERT(line!=NULL); - - *line = MoveNone; -} - -// line_copy() - -void line_copy(move_t dst[], const move_t src[]) { - - ASSERT(dst!=NULL); - ASSERT(src!=NULL); - - ASSERT(dst!=src); - - while ((*dst++ = *src++) != MoveNone) - ; -} - -// line_from_can() - -bool line_from_can (move_t line[], const board_t * board, const char string[], int size) { - - int pos; - char new_string[StringSize], *p; - int move; - board_t new_board[1]; - - ASSERT(line!=NULL); - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=LineSize); - - // init - - pos = 0; - board_copy(new_board,board); - - // loop - - strcpy(new_string,string); // HACK - - for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { - - move = move_from_can(p,new_board); - - ASSERT(move!=MoveNone); - ASSERT(move_is_legal(move,new_board)); - - if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves - - if (pos >= size) return FALSE; - line[pos++] = move; - - move_do(new_board,move); - } - - if (pos >= size) return FALSE; - line[pos] = MoveNone; - - return TRUE; -} - -// line_to_can() - -bool line_to_can(const move_t line[], const board_t * board, char string[], int size) { - - board_t new_board[1]; - int pos; - int move; - - ASSERT(line_is_ok(line)); - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=StringSize); - - // init - - if (size < StringSize) return FALSE; - - board_copy(new_board,board); - pos = 0; - - // loop - - while ((move = *line++) != MoveNone) { - - if (pos != 0) { - if (pos >= size) return FALSE; - string[pos++] = ' '; - } - - if (!move_to_can(move,new_board,&string[pos],size-pos)) return FALSE; - pos += strlen(&string[pos]); - - move_do(new_board,move); - } - - if (pos >= size) return FALSE; - string[pos] = '\0'; - - return TRUE; -} - -// line_to_san() - -bool line_to_san(const move_t line[], const board_t * board, char string[], int size) { - - board_t new_board[1]; - int pos; - int move; - char move_string[256]; - - ASSERT(line_is_ok(line)); - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=StringSize); - - // init - - if (size < StringSize) return FALSE; - - board_copy(new_board,board); - pos = 0; - - // loop - - while ((move = *line++) != MoveNone) { - - if (pos != 0) { - if (pos >= size) return FALSE; - string[pos++] = ' '; - } - - if (!move_is_legal(move,new_board) - || !move_to_san(move,new_board,&string[pos],size-pos)) { - - if (Strict || UseDebug) { - - move_to_can(move,new_board,move_string,256); - my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string); - - board_disp(new_board); - } - - if (Strict) my_fatal("line_to_san(): illegal move\n"); - - break; - } - - pos += strlen(&string[pos]); - - move_do(new_board,move); - } - - if (pos >= size) return FALSE; - string[pos] = '\0'; - - return TRUE; -} - -// end of line.cpp - + +// line.c + +// includes + +#include + +#include "board.h" +#include "line.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "san.h" +#include "util.h" + +// constants + +static const bool Strict = FALSE; // FALSE +static const bool UseDebug = FALSE; // FALSE + +// functions + +// line_is_ok() + +bool line_is_ok(const move_t line[]) { + + int move; + + if (line == NULL) return FALSE; + + while ((move = *line++) != MoveNone) { + if (!move_is_ok(move)) return FALSE; + } + + return TRUE; +} + +// line_clear() + +void line_clear(move_t line[]) { + + ASSERT(line!=NULL); + + *line = MoveNone; +} + +// line_copy() + +void line_copy(move_t dst[], const move_t src[]) { + + ASSERT(dst!=NULL); + ASSERT(src!=NULL); + + ASSERT(dst!=src); + + while ((*dst++ = *src++) != MoveNone) + ; +} + +// line_from_can() + +bool line_from_can (move_t line[], const board_t * board, const char string[], int size) { + + int pos; + char new_string[StringSize], *p; + int move; + board_t new_board[1]; + + ASSERT(line!=NULL); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=LineSize); + + // init + + pos = 0; + board_copy(new_board,board); + + // loop + + strcpy(new_string,string); // HACK + + for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { + + move = move_from_can(p,new_board); + + ASSERT(move!=MoveNone); + ASSERT(move_is_legal(move,new_board)); + + if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves + + if (pos >= size) return FALSE; + line[pos++] = move; + + move_do(new_board,move); + } + + if (pos >= size) return FALSE; + line[pos] = MoveNone; + + return TRUE; +} + +// line_to_can() + +bool line_to_can(const move_t line[], const board_t * board, char string[], int size) { + + board_t new_board[1]; + int pos; + int move; + + ASSERT(line_is_ok(line)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=StringSize); + + // init + + if (size < StringSize) return FALSE; + + board_copy(new_board,board); + pos = 0; + + // loop + + while ((move = *line++) != MoveNone) { + + if (pos != 0) { + if (pos >= size) return FALSE; + string[pos++] = ' '; + } + + if (!move_to_can(move,new_board,&string[pos],size-pos)) return FALSE; + pos += strlen(&string[pos]); + + move_do(new_board,move); + } + + if (pos >= size) return FALSE; + string[pos] = '\0'; + + return TRUE; +} + +// line_to_san() + +bool line_to_san(const move_t line[], const board_t * board, char string[], int size) { + + board_t new_board[1]; + int pos; + int move; + char move_string[256]; + + ASSERT(line_is_ok(line)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=StringSize); + + // init + + if (size < StringSize) return FALSE; + + board_copy(new_board,board); + pos = 0; + + // loop + + while ((move = *line++) != MoveNone) { + + if (pos != 0) { + if (pos >= size) return FALSE; + string[pos++] = ' '; + } + + if (!move_is_legal(move,new_board) + || !move_to_san(move,new_board,&string[pos],size-pos)) { + + if (Strict || UseDebug) { + + move_to_can(move,new_board,move_string,256); + my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string); + + board_disp(new_board); + } + + if (Strict) my_fatal("line_to_san(): illegal move\n"); + + break; + } + + pos += strlen(&string[pos]); + + move_do(new_board,move); + } + + if (pos >= size) return FALSE; + string[pos] = '\0'; + + return TRUE; +} + +// end of line.cpp + diff --git a/line.h b/line.h index 6460edf..7582d9a 100644 --- a/line.h +++ b/line.h @@ -1,32 +1,32 @@ - -// line.h - -#ifndef LINE_H -#define LINE_H - -// includes - -#include "board.h" -#include "move.h" -#include "util.h" - -// constants - -#define LineSize 256 - -// functions - -extern bool line_is_ok (const move_t line[]); - -extern void line_clear (move_t line[]); -extern void line_copy (move_t dst[], const move_t src[]); - -extern bool line_from_can (move_t line[], const board_t * board, const char string[], int size); - -extern bool line_to_can (const move_t line[], const board_t * board, char string[], int size); -extern bool line_to_san (const move_t line[], const board_t * board, char string[], int size); - -#endif // !defined LINE_H - -// end of line.h - + +// line.h + +#ifndef LINE_H +#define LINE_H + +// includes + +#include "board.h" +#include "move.h" +#include "util.h" + +// constants + +#define LineSize 256 + +// functions + +extern bool line_is_ok (const move_t line[]); + +extern void line_clear (move_t line[]); +extern void line_copy (move_t dst[], const move_t src[]); + +extern bool line_from_can (move_t line[], const board_t * board, const char string[], int size); + +extern bool line_to_can (const move_t line[], const board_t * board, char string[], int size); +extern bool line_to_san (const move_t line[], const board_t * board, char string[], int size); + +#endif // !defined LINE_H + +// end of line.h + diff --git a/list.c b/list.c index 4c2b08f..809efac 100644 --- a/list.c +++ b/list.c @@ -1,275 +1,275 @@ - -// list.c - -// includes - -#include "board.h" -#include "list.h" -#include "move.h" -#include "util.h" - -// functions - -// list_is_ok() - -bool list_is_ok(const list_t * list) { - - if (list == NULL) return FALSE; - - if (list->size >= ListSize) return FALSE; - - return TRUE; -} - -// list_clear() - -void list_clear(list_t * list) { - - ASSERT(list!=NULL); - - list->size = 0; -} - -// list_add - -void list_add(list_t * list, int move){ - list_add_ex(list, move, 0); -} - -// list_add_ex() - -void list_add_ex(list_t * list, int move, int value) { - - ASSERT(list_is_ok(list)); - ASSERT(move_is_ok(move)); - ASSERT(value>=-32767&&value<=+32767); - - ASSERT(list->sizemove[list->size] = move; - list->value[list->size] = value; - list->size++; -} - -// list_remove() - -void list_remove(list_t * list, int index) { - - int i; - - ASSERT(list_is_ok(list)); - ASSERT(index>=0&&indexsize); - - for (i = index; i < list->size-1; i++) { - list->move[i] = list->move[i+1]; - list->value[i] = list->value[i+1]; - } - - list->size--; -} - -// list_is_empty() - -bool list_is_empty(const list_t * list) { - - ASSERT(list_is_ok(list)); - - return list->size == 0; -} - -// list_size() - -int list_size(const list_t * list) { - - ASSERT(list_is_ok(list)); - - return list->size; -} - -// list_move() - -int list_move(const list_t * list, int index) { - - ASSERT(list_is_ok(list)); - ASSERT(index>=0&&indexsize); - - return list->move[index]; -} - -// list_value() - -int list_value(const list_t * list, int index) { - - ASSERT(list_is_ok(list)); - ASSERT(index>=0&&indexsize); - - return list->value[index]; -} - -// list_copy() - -void list_copy(list_t * dst, const list_t * src) { - - int i; - - ASSERT(dst!=NULL); - ASSERT(list_is_ok(src)); - - dst->size = src->size; - - for (i = 0; i < src->size; i++) { - dst->move[i] = src->move[i]; - dst->value[i] = src->value[i]; - } -} - -// list_move_to_front() - -void list_move_to_front(list_t * list, int index) { - - int i; - int move, value; - - ASSERT(list_is_ok(list)); - ASSERT(index>=0&&indexsize); - - if (index != 0) { - - move = list->move[index]; - value = list->value[index]; - - for (i = index; i > 0; i--) { - list->move[i] = list->move[i-1]; - list->value[i] = list->value[i-1]; - } - - list->move[0] = move; - list->value[0] = value; - } -} - -// list_note() - -void list_note(list_t * list) { - - int i, move; - - ASSERT(list_is_ok(list)); - - for (i = 0; i < list->size; i++) { - move = list->move[i]; - ASSERT(move_is_ok(move)); - list->value[i] = -move_order(move); - } -} - -// list_sort() - -void list_sort(list_t * list) { - - int i, j; - int best_index, best_move, best_value; - - ASSERT(list_is_ok(list)); - - for (i = 0; i < list->size-1; i++) { - - best_index = i; - best_value = list->value[i]; - - for (j = i+1; j < list->size; j++) { - if (list->value[j] > best_value) { - best_index = j; - best_value = list->value[j]; - } - } - - if (best_index != i) { - - best_move = list->move[best_index]; - ASSERT(best_value==list->value[best_index]); - - for (j = best_index; j > i; j--) { - list->move[j] = list->move[j-1]; - list->value[j] = list->value[j-1]; - } - - list->move[i] = best_move; - list->value[i] = best_value; - } - } - - if (DEBUG) { - for (i = 0; i < list->size-1; i++) { - ASSERT(list->value[i]>=list->value[i+1]); - } - } -} - -// list_contain() - -bool list_contain(const list_t * list, int move) { - - int i; - - ASSERT(list_is_ok(list)); - ASSERT(move_is_ok(move)); - - for (i = 0; i < list->size; i++) { - if (list->move[i] == move) return TRUE; - } - - return FALSE; -} - -// list_equal() - -bool list_equal(list_t * list_1, list_t * list_2) { - - list_t copy_1[1], copy_2[1]; - int i; - - ASSERT(list_is_ok(list_1)); - ASSERT(list_is_ok(list_2)); - - if (list_1->size != list_2->size) return FALSE; - - list_copy(copy_1,list_1); - list_note(copy_1); - list_sort(copy_1); - - list_copy(copy_2,list_2); - list_note(copy_2); - list_sort(copy_2); - - for (i = 0; i < copy_1->size; i++) { - if (copy_1->move[i] != copy_2->move[i]) return FALSE; - } - - return TRUE; -} - -// list_disp() - -void list_disp(const list_t * list, const board_t * board) { - - int i, move, value; - char string[256]; - - ASSERT(list_is_ok(list)); - ASSERT(board_is_ok(board)); - - for (i = 0; i < list->size; i++) { - - move = list->move[i]; - value = list->value[i]; - - if (!move_to_can(move,board,string,256)) ASSERT(FALSE); - my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value); - } - - my_log("POLYGLOT\n"); -} - -// end of list.cpp - + +// list.c + +// includes + +#include "board.h" +#include "list.h" +#include "move.h" +#include "util.h" + +// functions + +// list_is_ok() + +bool list_is_ok(const list_t * list) { + + if (list == NULL) return FALSE; + + if (list->size >= ListSize) return FALSE; + + return TRUE; +} + +// list_clear() + +void list_clear(list_t * list) { + + ASSERT(list!=NULL); + + list->size = 0; +} + +// list_add + +void list_add(list_t * list, int move){ + list_add_ex(list, move, 0); +} + +// list_add_ex() + +void list_add_ex(list_t * list, int move, int value) { + + ASSERT(list_is_ok(list)); + ASSERT(move_is_ok(move)); + ASSERT(value>=-32767&&value<=+32767); + + ASSERT(list->sizemove[list->size] = move; + list->value[list->size] = value; + list->size++; +} + +// list_remove() + +void list_remove(list_t * list, int index) { + + int i; + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + for (i = index; i < list->size-1; i++) { + list->move[i] = list->move[i+1]; + list->value[i] = list->value[i+1]; + } + + list->size--; +} + +// list_is_empty() + +bool list_is_empty(const list_t * list) { + + ASSERT(list_is_ok(list)); + + return list->size == 0; +} + +// list_size() + +int list_size(const list_t * list) { + + ASSERT(list_is_ok(list)); + + return list->size; +} + +// list_move() + +int list_move(const list_t * list, int index) { + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + return list->move[index]; +} + +// list_value() + +int list_value(const list_t * list, int index) { + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + return list->value[index]; +} + +// list_copy() + +void list_copy(list_t * dst, const list_t * src) { + + int i; + + ASSERT(dst!=NULL); + ASSERT(list_is_ok(src)); + + dst->size = src->size; + + for (i = 0; i < src->size; i++) { + dst->move[i] = src->move[i]; + dst->value[i] = src->value[i]; + } +} + +// list_move_to_front() + +void list_move_to_front(list_t * list, int index) { + + int i; + int move, value; + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + if (index != 0) { + + move = list->move[index]; + value = list->value[index]; + + for (i = index; i > 0; i--) { + list->move[i] = list->move[i-1]; + list->value[i] = list->value[i-1]; + } + + list->move[0] = move; + list->value[0] = value; + } +} + +// list_note() + +void list_note(list_t * list) { + + int i, move; + + ASSERT(list_is_ok(list)); + + for (i = 0; i < list->size; i++) { + move = list->move[i]; + ASSERT(move_is_ok(move)); + list->value[i] = -move_order(move); + } +} + +// list_sort() + +void list_sort(list_t * list) { + + int i, j; + int best_index, best_move, best_value; + + ASSERT(list_is_ok(list)); + + for (i = 0; i < list->size-1; i++) { + + best_index = i; + best_value = list->value[i]; + + for (j = i+1; j < list->size; j++) { + if (list->value[j] > best_value) { + best_index = j; + best_value = list->value[j]; + } + } + + if (best_index != i) { + + best_move = list->move[best_index]; + ASSERT(best_value==list->value[best_index]); + + for (j = best_index; j > i; j--) { + list->move[j] = list->move[j-1]; + list->value[j] = list->value[j-1]; + } + + list->move[i] = best_move; + list->value[i] = best_value; + } + } + + if (DEBUG) { + for (i = 0; i < list->size-1; i++) { + ASSERT(list->value[i]>=list->value[i+1]); + } + } +} + +// list_contain() + +bool list_contain(const list_t * list, int move) { + + int i; + + ASSERT(list_is_ok(list)); + ASSERT(move_is_ok(move)); + + for (i = 0; i < list->size; i++) { + if (list->move[i] == move) return TRUE; + } + + return FALSE; +} + +// list_equal() + +bool list_equal(list_t * list_1, list_t * list_2) { + + list_t copy_1[1], copy_2[1]; + int i; + + ASSERT(list_is_ok(list_1)); + ASSERT(list_is_ok(list_2)); + + if (list_1->size != list_2->size) return FALSE; + + list_copy(copy_1,list_1); + list_note(copy_1); + list_sort(copy_1); + + list_copy(copy_2,list_2); + list_note(copy_2); + list_sort(copy_2); + + for (i = 0; i < copy_1->size; i++) { + if (copy_1->move[i] != copy_2->move[i]) return FALSE; + } + + return TRUE; +} + +// list_disp() + +void list_disp(const list_t * list, const board_t * board) { + + int i, move, value; + char string[256]; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + for (i = 0; i < list->size; i++) { + + move = list->move[i]; + value = list->value[i]; + + if (!move_to_can(move,board,string,256)) ASSERT(FALSE); + my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value); + } + + my_log("POLYGLOT\n"); +} + +// end of list.cpp + diff --git a/list.h b/list.h index d366896..c3ffb41 100644 --- a/list.h +++ b/list.h @@ -1,54 +1,54 @@ - -// list.h - -#ifndef LIST_H -#define LIST_H - -// includes - -#include "board.h" -#include "move.h" -#include "util.h" - -// defines - -#define ListSize 256 - -// types - -typedef struct { - sint16 size; - move_t move[ListSize]; - sint16 value[ListSize]; -} list_t; - -// functions - -extern bool list_is_ok (const list_t * list); - -extern void list_clear (list_t * list); -extern void list_add (list_t * list, int move); -extern void list_add_ex (list_t * list, int move, int value); - -extern void list_remove (list_t * list, int index); - -extern bool list_is_empty (const list_t * list); -extern int list_size (const list_t * list); - -extern int list_move (const list_t * list, int index); -extern int list_value (const list_t * list, int index); - -extern void list_copy (list_t * dst, const list_t * src); - -extern void list_note (list_t * list); -extern void list_sort (list_t * list); - -extern bool list_contain (const list_t * list, int move); -extern bool list_equal (list_t * list_1, list_t * list_2); - -extern void list_disp (const list_t * list, const board_t * board); - -#endif // !defined LIST_H - -// end of list.h - + +// list.h + +#ifndef LIST_H +#define LIST_H + +// includes + +#include "board.h" +#include "move.h" +#include "util.h" + +// defines + +#define ListSize 256 + +// types + +typedef struct { + sint16 size; + move_t move[ListSize]; + sint16 value[ListSize]; +} list_t; + +// functions + +extern bool list_is_ok (const list_t * list); + +extern void list_clear (list_t * list); +extern void list_add (list_t * list, int move); +extern void list_add_ex (list_t * list, int move, int value); + +extern void list_remove (list_t * list, int index); + +extern bool list_is_empty (const list_t * list); +extern int list_size (const list_t * list); + +extern int list_move (const list_t * list, int index); +extern int list_value (const list_t * list, int index); + +extern void list_copy (list_t * dst, const list_t * src); + +extern void list_note (list_t * list); +extern void list_sort (list_t * list); + +extern bool list_contain (const list_t * list, int move); +extern bool list_equal (list_t * list_1, list_t * list_2); + +extern void list_disp (const list_t * list, const board_t * board); + +#endif // !defined LIST_H + +// end of list.h + diff --git a/main.c b/main.c index 5400507..f2847b9 100644 --- a/main.c +++ b/main.c @@ -1,671 +1,670 @@ - -// main.c - -// includes - -#include -#include -#include -#include -#include - -#include "attack.h" -#include "board.h" -#include "book.h" -#include "book_make.h" -#include "book_merge.h" -#include "engine.h" -#include "epd.h" -#include "fen.h" -#include "gui.h" -#include "hash.h" -#include "list.h" -#include "main.h" -#include "mainloop.h" -#include "move.h" -#include "move_gen.h" -#include "option.h" -#include "piece.h" -#include "search.h" -#include "square.h" -#include "uci.h" -#include "util.h" -#include "xboard2uci.h" -#include "uci2uci.h" -#include "ini.h" -#include "util.h" - - -// constants - - -static const char * const Version = "1.4.61b"; -static const char * const HelpMessage = "\ -SYNTAX\n\ -* polyglot [configfile] [-noini] [-ec engine] [-ed enginedirectory] [-en enginename] [-log true/false] [-lf logfile] [-pg =]* [-uci =]*\n\ -* polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\ -* polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\ -* polyglot info-book [-bin inputfile] [-exact]\n\ -* polyglot dump-book [-bin inputfile] -color color [-out outputfile]\n\ -* polyglot [configfile] epd-test [engineoptions] [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\ -* polyglot perft [-fen fen] [-max-depth depth]\ -"; - -static const int SearchDepth = 63; -static const double SearchTime = 3600.0; -static const int StringSize = 4096; - -// variables - -static bool Init; - -// prototypes - -static void stop_search (); - -// functions - -// arg_shift_left() - -static void arg_shift_left(char **argv, int index){ - int i; - for(i=index; argv[i]!=NULL; i++){ - argv[i]=argv[i+1]; - } -} - -// parse_args() - -static void parse_args(ini_t *ini, char **argv){ - int arg_index; - char *arg; - arg_index=0; - while((arg=argv[arg_index])){ - if(my_string_equal(arg,"-ec") && argv[arg_index+1]){ - ini_insert_ex(ini,"PolyGlot","EngineCommand",argv[arg_index+1]); - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - }if(my_string_equal(arg,"-ed") && argv[arg_index+1]){ - ini_insert_ex(ini,"PolyGlot","EngineDir",argv[arg_index+1]); - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - } - if(my_string_equal(arg,"-en") && argv[arg_index+1]){ - ini_insert_ex(ini,"PolyGlot","EngineName",argv[arg_index+1]); - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - } - if(my_string_equal(arg,"-log") && - argv[arg_index+1] && - IS_BOOL(argv[arg_index+1])){ - ini_insert_ex(ini, - "PolyGlot", - "Log", - TO_BOOL(argv[arg_index+1])?"true":"false"); - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - } - if(my_string_equal(arg,"-lf") && argv[arg_index+1]){ - ini_insert_ex(ini,"PolyGlot","LogFile",argv[arg_index+1]); - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - } - if(my_string_equal(arg,"-wb") && - argv[arg_index+1]&& - IS_BOOL(argv[arg_index+1])){ - ini_insert_ex(ini,"PolyGlot", - "OnlyWbOptions", - TO_BOOL(argv[arg_index+1])?"true":"false"); - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - } - if((my_string_equal(arg,"-pg")||my_string_equal(arg,"-uci")) && - argv[arg_index+1]){ - int ret; - char section[StringSize]; - char name[StringSize]; - char value[StringSize]; - ret=ini_line_parse(argv[arg_index+1],section,name,value); - if(ret==NAME_VALUE){ - if(my_string_equal(arg,"-pg")){ - ini_insert_ex(ini,"PolyGlot",name,value); - }else{ - ini_insert_ex(ini,"Engine",name,value); - } - } - arg_shift_left(argv,arg_index); - arg_shift_left(argv,arg_index); - continue; - } - arg_index++; - } -} - - -// make_ini() - -static void make_ini(ini_t *ini){ - option_t *opt; - ini_insert_ex(ini,"polyglot", - "EngineCommand", - option_get(Option,"EngineCommand")); - ini_insert_ex(ini,"polyglot", - "EngineDir", - option_get(Option,"EngineDir")); - option_start_iter(Option); - while((opt=option_next(Option))){ - if(my_string_case_equal(opt->name,"SettingsFile")) continue; - if(my_string_case_equal(opt->name,"EngineCommand")) continue; - if(my_string_case_equal(opt->name,"EngineDir")) continue; - if(!my_string_equal(opt->value,opt->default_)&& !IS_BUTTON(opt->type)) - { - ini_insert_ex(ini,"polyglot",opt->name,opt->value); - } - } - option_start_iter(Uci->option); - while((opt=option_next(Uci->option))){ - if(!strncmp(opt->name,"UCI_",4) && - !my_string_case_equal(opt->name,"UCI_LimitStrength") && - !my_string_case_equal(opt->name,"UCI_Elo"))continue; - if(!my_string_equal(opt->value,opt->default_)&& - !IS_BUTTON(opt->type)){ - ini_insert_ex(ini,"engine",opt->name,opt->value); - } - } -} - - -// write_ini() - -static void write_ini(const char *filename, - ini_t *ini){ - // TODO Quote, dequote - const char *quote; - ini_entry_t *entry; - char tmp[StringSize]; - char tmp1[StringSize]; - char tmp2[StringSize]; - FILE *f; - time_t t=time(NULL); - f=fopen(filename,"w"); - if(!f){ - gui_send(GUI,"tellusererror write_ini(): %s: %s.",filename,strerror(errno)); - my_log("POLYGLOT write_ini(): %s: %s.\n",filename,strerror(errno)); - return; - } - fprintf(f,"; Created: %s\n",ctime(&t)); - fprintf(f,"[PolyGlot]\n"); - ini_start_iter(ini); - while((entry=ini_next(ini))){ - if(my_string_case_equal(entry->section,"polyglot")){ - my_quote(tmp1,entry->name,ini_specials); - my_quote(tmp2,entry->value,ini_specials); - snprintf(tmp,sizeof(tmp),"%s=%s\n", - tmp1, - tmp2); - tmp[sizeof(tmp)-1]='\0'; - fprintf(f,"%s",tmp); - } - } - fprintf(f,"[Engine]\n"); - ini_start_iter(ini); - while((entry=ini_next(ini))){ - if(my_string_case_equal(entry->section,"engine")){ - my_quote(tmp1,entry->name,ini_specials); - my_quote(tmp2,entry->value,ini_specials); - snprintf(tmp,sizeof(tmp),"%s=%s\n", - tmp1, - tmp2); - tmp[sizeof(tmp)-1]='\0'; - fprintf(f,"%s",tmp); - } - } - fclose(f); -} - -// welcome_message() - -void welcome_message(char *buf){ - if(!DEBUG){ - sprintf(buf, - "PolyGlot %s by Fabien Letouzey.\n", - Version); - }else{ - sprintf(buf, - "PolyGlot %s by Fabien Letouzey (debug build).\n", - Version); - } -} - -int wb_select(){ - option_t *opt; - option_start_iter(Option); - while((opt=option_next(Option))){ - opt->mode&=~XBOARD; - if(opt->mode & XBSEL){ - opt->mode|=XBOARD; - } - } -} - -// main() - -int main(int argc, char * argv[]) { - ini_t ini[1], ini_command[1]; - ini_entry_t *entry; - char *arg; - int arg_index; - bool NoIni; - option_t *opt; - char welcome[StringSize]; - - - welcome_message(welcome); - - printf("%s",welcome); - - - if(argc>=2 && ((my_string_case_equal(argv[1],"help")) || (my_string_case_equal(argv[1],"-help")) || (my_string_case_equal(argv[1],"--help")) || (my_string_case_equal(argv[1],"-h")) || my_string_case_equal(argv[1],"/?"))){ - printf("%s\n",HelpMessage); - return EXIT_SUCCESS; - } - - // init - - Init = FALSE; - - gui_init(GUI); - - util_init(); - option_init_pg(); - - square_init(); - piece_init(); - attack_init(); - - hash_init(); - - my_random_init(); - - ini_init(ini); - ini_init(ini_command); - - // book utilities: do not touch these - - if (argc >= 2 && my_string_equal(argv[1],"make-book")) { - book_make(argc,argv); - return EXIT_SUCCESS; - } - - if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { - book_merge(argc,argv); - return EXIT_SUCCESS; - } - - if (argc >= 2 && my_string_equal(argv[1],"dump-book")) { - book_dump(argc,argv); - return EXIT_SUCCESS; - } - - if (argc >= 2 && my_string_equal(argv[1],"info-book")) { - book_info(argc,argv); - return EXIT_SUCCESS; - } - - // perft - - if (argc >= 2 && my_string_equal(argv[1],"perft")) { - do_perft(argc,argv); - return EXIT_SUCCESS; - } - - // What is the config file? This is very hacky right now. - - // Do we want a config file at all? - - arg_index=0; - NoIni=FALSE; - while((arg=argv[arg_index++])){ - if(my_string_equal(arg,"-noini")){ - NoIni=TRUE; - break; - } - } - arg_shift_left(argv,arg_index-1); - parse_args(ini_command,argv+1); - if(NoIni){ - option_set(Option,"SettingsFile",""); - } - - // Ok see if first argument looks like config file - - if(argv[1] && !my_string_equal(argv[1],"epd-test") && !(argv[1][0]=='-')){ - // first argument must be config file - if(!NoIni){ - option_set(Option,"SettingsFile",argv[1]); - }else{ - // ignore - } - arg_shift_left(argv,1); - }else{ - // Config file is the default. - // This has already been set above or in "option_init_pg()" - } - - - - // if we use a config file: load it! - - if(!my_string_equal(option_get_string(Option,"SettingsFile"),"")){ - if(ini_parse(ini,option_get_string(Option,"SettingsFile"))){ - my_fatal("main(): Can't open config file \"%s\": %s\n", - option_get_string(Option,"SettingsFile"), - strerror(errno)); - } - } - - // Extract some important options - - if((entry=ini_find(ini,"polyglot","EngineCommand"))){ - option_set(Option,entry->name,entry->value); - } - if((entry=ini_find(ini,"polyglot","EngineDir"))){ - option_set(Option,entry->name,entry->value); - } - if((entry=ini_find(ini,"polyglot","EngineName"))){ - option_set(Option,entry->name,entry->value); - } - if((entry=ini_find(ini,"polyglot","Log"))){ - polyglot_set_option(entry->name,entry->value); - } - if((entry=ini_find(ini,"polyglot","LogFile"))){ - polyglot_set_option(entry->name,entry->value); - } - - // Concession to WB 4.4.0 - // Treat "polyglot_1st.ini" and "polyglot_2nd.ini" specially - - if(option_get_bool(Option,"WbWorkArounds3")){ - const char *SettingsFile=option_get(Option,"SettingsFile"); - if(strstr(SettingsFile,"polyglot_1st.ini")|| - strstr(SettingsFile,"polyglot_2nd.ini")){ - option_set(Option,"SettingsFile",""); - } - } - - // Look at command line for logging option. It is important - // to start logging as soon as possible. - - if((entry=ini_find(ini_command,"PolyGlot","Log"))){ - option_set(Option,entry->name,entry->value); - } - if((entry=ini_find(ini_command,"PolyGlot","LogFile"))){ - option_set(Option,entry->name,entry->value); - } - - // start logging if required - - if (option_get_bool(Option,"Log")) { - my_log_open(option_get_string(Option,"LogFile")); - } - - // log welcome stuff - - my_log("%s",welcome); - my_log("POLYGLOT *** START ***\n"); - if(!my_string_equal(option_get_string(Option,"SettingsFile"),"")){ - my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"SettingsFile")); - } - - - // scavenge command line for options necessary to start the engine - - - if((entry=ini_find(ini_command,"PolyGlot","EngineCommand"))){ - option_set(Option,entry->name,entry->value); - } - if((entry=ini_find(ini_command,"PolyGlot","EngineDir"))){ - option_set(Option,entry->name,entry->value); - } - if((entry=ini_find(ini_command,"PolyGlot","EngineName"))){ - option_set(Option,entry->name,entry->value); - } - - // Make sure that EngineCommand has been set - if(my_string_case_equal(option_get(Option,"EngineCommand"),"")){ - my_fatal("main(): EngineCommand not set\n"); - } - - // start engine - - engine_open(Engine); - - if(!engine_active(Engine)){ - my_fatal("main(): Could not start \"%s\"\n",option_get(Option,"EngineCommand")); - } - - // switch to UCI mode if necessary - - if (option_get_bool(Option,"UCI")) { - my_log("POLYGLOT *** Switching to UCI mode ***\n"); - } - - // initialize uci parsing and send uci command. - // Parse options and wait for uciok - - // XXX - uci_open(Uci,Engine); - - option_set_default(Option,"EngineName",Uci->name); - - // get engine name from engine if not supplied in config file or on - // the command line - - if (my_string_equal(option_get_string(Option,"EngineName"),"")) { - option_set(Option,"EngineName",Uci->name); - } - - - // In the case we have been invoked with NoIni or StandardIni - // we still have to load a config file. - - if(my_string_equal(option_get_string(Option,"SettingsFile"),"")){ - - // construct the name of the ConfigFile from the EngineName - - char tmp[StringSize]; - char option_file[StringSize]; - int i; - snprintf(tmp,sizeof(tmp),"%s.ini", - option_get_string(Option,"EngineName")); - tmp[sizeof(tmp)-1]='\0'; - for(i=0;isection,"polyglot")){ - opt=option_find(Option,entry->name); - if(opt && !IS_BUTTON(opt->type)){ - polyglot_set_option(entry->name,entry->value); - } - } - } - - // Cater to our biggest customer:-) - - if(option_get_bool(Option,"OnlyWbOptions")){ - wb_select(); - } - - // done initializing - - Init = TRUE; - - // collect engine options from config file(s) and send to engine - - ini_start_iter(ini); - while((entry=ini_next(ini))){ - if(my_string_case_equal(entry->section,"engine")){ - // also updates value in Uci->option - uci_send_option(Uci,entry->name,"%s",entry->value); - } - } - - - - // EPD test - - if (argv[1] && my_string_equal(argv[1],"epd-test")){ - argc=0; - while((arg=argv[argc++])); - epd_test(argc-1,argv); - return EXIT_SUCCESS; - } - - // Anything that hasn't been parsed yet is a syntax error - // It seems that XBoard sometimes passes empty strings as arguments - // to PolyGlot. We ignore these. - - argc=1; - while((arg=argv[argc++])){ - if(!my_string_equal(arg,"")){ - my_fatal("main(): Incorrect use of option: \"%s\"\n",argv[argc-1]); - } - } - - // gui_init(GUI); - mainloop(); - return EXIT_SUCCESS; -} - -// polyglot_set_option() - -void polyglot_set_option(const char *name, const char *value){ // this must be cleaned up! - ini_t ini[1]; - int ret; - ini_init(ini); - my_log("POLYGLOT Setting PolyGlot option \"%s=%s\"\n",name,value); - if(my_string_case_equal(name,"Save")){ - ret=my_mkdir(option_get(Option,"SettingsDir")); - if(ret){ - my_log("POLYGLOT polyglot_set_option(): %s: %s\n", - option_get(Option,"SettingsDir"), - strerror(errno)); - } - make_ini(ini); - write_ini(option_get(Option,"SettingsFile"),ini); - return; - } -// if(my_string_equal(option_get(Option,name),value)){ -// my_log("Not setting PolyGlot option \"%s\" " -// "since it already as the correct value.\n", -// name); -// return; -// } - option_set(Option,name,value); - if(option_get_bool(Option,"Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){ - my_log("POLYGLOT *** SETTING BOOK ***\n"); - my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile")); - book_close(); - book_clear(); - book_open(option_get_string(Option,"BookFile")); - if(!book_is_open()){ - my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string(Option,"BookFile")); - } - }else if(option_get_bool(Option,"Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){ - my_log("POLYGLOT *** SWITCHING LOGFILE ***\n"); - my_log("POLYGLOT NEW LOGFILE \"%s\"\n",option_get_string(Option,"LogFile")); - my_log_close(); - my_log_open(option_get_string(Option,"LogFile")); - }else if(option_get_bool(Option,"UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){ - my_log("POLYGLOT Adjust Engine Piority\n"); - engine_set_nice_value(Engine,atoi(option_get_string(Option,"NiceValue"))); - }else if(my_string_case_equal(name,"Book") && !option_get_bool(Option,"Book")){ - book_close(); - book_clear(); - }else if(my_string_case_equal(name,"UseNice") && !option_get_bool(Option,"UseNice")){ - my_log("POLYGLOT Adjust Engine Piority\n"); - engine_set_nice_value(Engine,0); - }else if(my_string_case_equal(name,"Log") && !option_get_bool(Option,"Log")){ - my_log("POLYGLOT QUIT LOGGING\n"); - my_log_close(); - } -} - - - -// quit() - -void quit() { - my_log("POLYGLOT *** QUIT ***\n"); - if (Init && !Engine->pipex->quit_pending) { - stop_search(); - Engine->pipex->quit_pending=TRUE; - engine_send(Engine,"quit"); - engine_close(Engine); - - } - my_sleep(200); - my_log("POLYGLOT Calling exit\n"); - exit(EXIT_SUCCESS); -} - -// stop_search() - -static void stop_search() { - - if (Init && Uci->searching) { - - ASSERT(Uci->searching); - ASSERT(Uci->pending_nb>=1); - - my_log("POLYGLOT STOP SEARCH\n"); - - if (option_get_bool(Option,"SyncStop")) { - uci_send_stop_sync(Uci); - } else { - uci_send_stop(Uci); - } - } -} - - -// end of main.c - + +// main.c + +// includes + +#include +#include +#include +#include +#include + +#include "attack.h" +#include "board.h" +#include "book.h" +#include "book_make.h" +#include "book_merge.h" +#include "engine.h" +#include "epd.h" +#include "fen.h" +#include "gui.h" +#include "hash.h" +#include "list.h" +#include "main.h" +#include "mainloop.h" +#include "move.h" +#include "move_gen.h" +#include "option.h" +#include "piece.h" +#include "search.h" +#include "square.h" +#include "uci.h" +#include "util.h" +#include "xboard2uci.h" +#include "uci2uci.h" +#include "ini.h" +#include "util.h" + + +// constants + + +static const char * const Version = "1.4.63b"; +static const char * const HelpMessage = "\ +SYNTAX\n\ +* polyglot [configfile] [-noini] [-ec engine] [-ed enginedirectory] [-en enginename] [-log true/false] [-lf logfile] [-pg =]* [-uci =]*\n\ +* polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\ +* polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\ +* polyglot info-book [-bin inputfile] [-exact]\n\ +* polyglot dump-book [-bin inputfile] -color color [-out outputfile]\n\ +* polyglot [configfile] epd-test [engineoptions] [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\ +* polyglot perft [-fen fen] [-max-depth depth]\ +"; + +static const int SearchDepth = 63; +static const double SearchTime = 3600.0; + +// variables + +static bool Init; + +// prototypes + +static void stop_search (); + +// functions + +// arg_shift_left() + +static void arg_shift_left(char **argv, int index){ + int i; + for(i=index; argv[i]!=NULL; i++){ + argv[i]=argv[i+1]; + } +} + +// parse_args() + +static void parse_args(ini_t *ini, char **argv){ + int arg_index; + char *arg; + arg_index=0; + while((arg=argv[arg_index])){ + if(my_string_equal(arg,"-ec") && argv[arg_index+1]){ + ini_insert_ex(ini,"PolyGlot","EngineCommand",argv[arg_index+1]); + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + }if(my_string_equal(arg,"-ed") && argv[arg_index+1]){ + ini_insert_ex(ini,"PolyGlot","EngineDir",argv[arg_index+1]); + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + } + if(my_string_equal(arg,"-en") && argv[arg_index+1]){ + ini_insert_ex(ini,"PolyGlot","EngineName",argv[arg_index+1]); + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + } + if(my_string_equal(arg,"-log") && + argv[arg_index+1] && + IS_BOOL(argv[arg_index+1])){ + ini_insert_ex(ini, + "PolyGlot", + "Log", + TO_BOOL(argv[arg_index+1])?"true":"false"); + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + } + if(my_string_equal(arg,"-lf") && argv[arg_index+1]){ + ini_insert_ex(ini,"PolyGlot","LogFile",argv[arg_index+1]); + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + } + if(my_string_equal(arg,"-wb") && + argv[arg_index+1]&& + IS_BOOL(argv[arg_index+1])){ + ini_insert_ex(ini,"PolyGlot", + "OnlyWbOptions", + TO_BOOL(argv[arg_index+1])?"true":"false"); + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + } + if((my_string_equal(arg,"-pg")||my_string_equal(arg,"-uci")) && + argv[arg_index+1]){ + int ret; + char section[StringSize]; + char name[StringSize]; + char value[StringSize]; + ret=ini_line_parse(argv[arg_index+1],section,name,value); + if(ret==NAME_VALUE){ + if(my_string_equal(arg,"-pg")){ + ini_insert_ex(ini,"PolyGlot",name,value); + }else{ + ini_insert_ex(ini,"Engine",name,value); + } + } + arg_shift_left(argv,arg_index); + arg_shift_left(argv,arg_index); + continue; + } + arg_index++; + } +} + + +// make_ini() + +static void make_ini(ini_t *ini){ + option_t *opt; + ini_insert_ex(ini,"polyglot", + "EngineCommand", + option_get(Option,"EngineCommand")); + ini_insert_ex(ini,"polyglot", + "EngineDir", + option_get(Option,"EngineDir")); + option_start_iter(Option); + while((opt=option_next(Option))){ + if(my_string_case_equal(opt->name,"SettingsFile")) continue; + if(my_string_case_equal(opt->name,"EngineCommand")) continue; + if(my_string_case_equal(opt->name,"EngineDir")) continue; + if(!my_string_equal(opt->value,opt->default_)&& !IS_BUTTON(opt->type)) + { + ini_insert_ex(ini,"polyglot",opt->name,opt->value); + } + } + option_start_iter(Uci->option); + while((opt=option_next(Uci->option))){ + if(!strncmp(opt->name,"UCI_",4) && + !my_string_case_equal(opt->name,"UCI_LimitStrength") && + !my_string_case_equal(opt->name,"UCI_Elo"))continue; + if(!my_string_equal(opt->value,opt->default_)&& + !IS_BUTTON(opt->type)){ + ini_insert_ex(ini,"engine",opt->name,opt->value); + } + } +} + + +// write_ini() + +static void write_ini(const char *filename, + ini_t *ini){ + // TODO Quote, dequote + const char *quote; + ini_entry_t *entry; + char tmp[StringSize]; + char tmp1[StringSize]; + char tmp2[StringSize]; + FILE *f; + time_t t=time(NULL); + f=fopen(filename,"w"); + if(!f){ + gui_send(GUI,"tellusererror write_ini(): %s: %s.",filename,strerror(errno)); + my_log("POLYGLOT write_ini(): %s: %s.\n",filename,strerror(errno)); + return; + } + fprintf(f,"; Created: %s\n",ctime(&t)); + fprintf(f,"[PolyGlot]\n"); + ini_start_iter(ini); + while((entry=ini_next(ini))){ + if(my_string_case_equal(entry->section,"polyglot")){ + my_quote(tmp1,entry->name,ini_specials); + my_quote(tmp2,entry->value,ini_specials); + snprintf(tmp,sizeof(tmp),"%s=%s\n", + tmp1, + tmp2); + tmp[sizeof(tmp)-1]='\0'; + fprintf(f,"%s",tmp); + } + } + fprintf(f,"[Engine]\n"); + ini_start_iter(ini); + while((entry=ini_next(ini))){ + if(my_string_case_equal(entry->section,"engine")){ + my_quote(tmp1,entry->name,ini_specials); + my_quote(tmp2,entry->value,ini_specials); + snprintf(tmp,sizeof(tmp),"%s=%s\n", + tmp1, + tmp2); + tmp[sizeof(tmp)-1]='\0'; + fprintf(f,"%s",tmp); + } + } + fclose(f); +} + +// welcome_message() + +void welcome_message(char *buf){ + if(!DEBUG){ + sprintf(buf, + "PolyGlot %s by Fabien Letouzey.\n", + Version); + }else{ + sprintf(buf, + "PolyGlot %s by Fabien Letouzey (debug build).\n", + Version); + } +} + +int wb_select(){ + option_t *opt; + option_start_iter(Option); + while((opt=option_next(Option))){ + opt->mode&=~XBOARD; + if(opt->mode & XBSEL){ + opt->mode|=XBOARD; + } + } +} + +// main() + +int main(int argc, char * argv[]) { + ini_t ini[1], ini_command[1]; + ini_entry_t *entry; + char *arg; + int arg_index; + bool NoIni; + option_t *opt; + char welcome[StringSize]; + + + welcome_message(welcome); + + printf("%s",welcome); + + + if(argc>=2 && ((my_string_case_equal(argv[1],"help")) || (my_string_case_equal(argv[1],"-help")) || (my_string_case_equal(argv[1],"--help")) || (my_string_case_equal(argv[1],"-h")) || my_string_case_equal(argv[1],"/?"))){ + printf("%s\n",HelpMessage); + return EXIT_SUCCESS; + } + + // init + + Init = FALSE; + + gui_init(GUI); + + util_init(); + option_init_pg(); + + square_init(); + piece_init(); + attack_init(); + + hash_init(); + + my_random_init(); + + ini_init(ini); + ini_init(ini_command); + + // book utilities: do not touch these + + if (argc >= 2 && my_string_equal(argv[1],"make-book")) { + book_make(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { + book_merge(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"dump-book")) { + book_dump(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"info-book")) { + book_info(argc,argv); + return EXIT_SUCCESS; + } + + // perft + + if (argc >= 2 && my_string_equal(argv[1],"perft")) { + do_perft(argc,argv); + return EXIT_SUCCESS; + } + + // What is the config file? This is very hacky right now. + + // Do we want a config file at all? + + arg_index=0; + NoIni=FALSE; + while((arg=argv[arg_index++])){ + if(my_string_equal(arg,"-noini")){ + NoIni=TRUE; + break; + } + } + arg_shift_left(argv,arg_index-1); + parse_args(ini_command,argv+1); + if(NoIni){ + option_set(Option,"SettingsFile",""); + } + + // Ok see if first argument looks like config file + + if(argv[1] && !my_string_equal(argv[1],"epd-test") && !(argv[1][0]=='-')){ + // first argument must be config file + if(!NoIni){ + option_set(Option,"SettingsFile",argv[1]); + }else{ + // ignore + } + arg_shift_left(argv,1); + }else{ + // Config file is the default. + // This has already been set above or in "option_init_pg()" + } + + + + // if we use a config file: load it! + + if(!my_string_equal(option_get_string(Option,"SettingsFile"),"")){ + if(ini_parse(ini,option_get_string(Option,"SettingsFile"))){ + my_fatal("main(): Can't open config file \"%s\": %s\n", + option_get_string(Option,"SettingsFile"), + strerror(errno)); + } + } + + // Extract some important options + + if((entry=ini_find(ini,"polyglot","EngineCommand"))){ + option_set(Option,entry->name,entry->value); + } + if((entry=ini_find(ini,"polyglot","EngineDir"))){ + option_set(Option,entry->name,entry->value); + } + if((entry=ini_find(ini,"polyglot","EngineName"))){ + option_set(Option,entry->name,entry->value); + } + if((entry=ini_find(ini,"polyglot","Log"))){ + polyglot_set_option(entry->name,entry->value); + } + if((entry=ini_find(ini,"polyglot","LogFile"))){ + polyglot_set_option(entry->name,entry->value); + } + + // Concession to WB 4.4.0 + // Treat "polyglot_1st.ini" and "polyglot_2nd.ini" specially + + if(option_get_bool(Option,"WbWorkArounds3")){ + const char *SettingsFile=option_get(Option,"SettingsFile"); + if(strstr(SettingsFile,"polyglot_1st.ini")|| + strstr(SettingsFile,"polyglot_2nd.ini")){ + option_set(Option,"SettingsFile",""); + } + } + + // Look at command line for logging option. It is important + // to start logging as soon as possible. + + if((entry=ini_find(ini_command,"PolyGlot","Log"))){ + option_set(Option,entry->name,entry->value); + } + if((entry=ini_find(ini_command,"PolyGlot","LogFile"))){ + option_set(Option,entry->name,entry->value); + } + + // start logging if required + + if (option_get_bool(Option,"Log")) { + my_log_open(option_get_string(Option,"LogFile")); + } + + // log welcome stuff + + my_log("%s",welcome); + my_log("POLYGLOT *** START ***\n"); + if(!my_string_equal(option_get_string(Option,"SettingsFile"),"")){ + my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"SettingsFile")); + } + + + // scavenge command line for options necessary to start the engine + + + if((entry=ini_find(ini_command,"PolyGlot","EngineCommand"))){ + option_set(Option,entry->name,entry->value); + } + if((entry=ini_find(ini_command,"PolyGlot","EngineDir"))){ + option_set(Option,entry->name,entry->value); + } + if((entry=ini_find(ini_command,"PolyGlot","EngineName"))){ + option_set(Option,entry->name,entry->value); + } + + // Make sure that EngineCommand has been set + if(my_string_case_equal(option_get(Option,"EngineCommand"),"")){ + my_fatal("main(): EngineCommand not set\n"); + } + + // start engine + + engine_open(Engine); + + if(!engine_active(Engine)){ + my_fatal("main(): Could not start \"%s\"\n",option_get(Option,"EngineCommand")); + } + + // switch to UCI mode if necessary + + if (option_get_bool(Option,"UCI")) { + my_log("POLYGLOT *** Switching to UCI mode ***\n"); + } + + // initialize uci parsing and send uci command. + // Parse options and wait for uciok + + // XXX + uci_open(Uci,Engine); + + option_set_default(Option,"EngineName",Uci->name); + + // get engine name from engine if not supplied in config file or on + // the command line + + if (my_string_equal(option_get_string(Option,"EngineName"),"")) { + option_set(Option,"EngineName",Uci->name); + } + + + // In the case we have been invoked with NoIni or StandardIni + // we still have to load a config file. + + if(my_string_equal(option_get_string(Option,"SettingsFile"),"")){ + + // construct the name of the ConfigFile from the EngineName + + char tmp[StringSize]; + char option_file[StringSize]; + int i; + snprintf(tmp,sizeof(tmp),"%s.ini", + option_get_string(Option,"EngineName")); + tmp[sizeof(tmp)-1]='\0'; + for(i=0;isection,"polyglot")){ + opt=option_find(Option,entry->name); + if(opt && !IS_BUTTON(opt->type)){ + polyglot_set_option(entry->name,entry->value); + } + } + } + + // Cater to our biggest customer:-) + + if(option_get_bool(Option,"OnlyWbOptions")){ + wb_select(); + } + + // done initializing + + Init = TRUE; + + // collect engine options from config file(s) and send to engine + + ini_start_iter(ini); + while((entry=ini_next(ini))){ + if(my_string_case_equal(entry->section,"engine")){ + // also updates value in Uci->option + uci_send_option(Uci,entry->name,"%s",entry->value); + } + } + + + + // EPD test + + if (argv[1] && my_string_equal(argv[1],"epd-test")){ + argc=0; + while((arg=argv[argc++])); + epd_test(argc-1,argv); + return EXIT_SUCCESS; + } + + // Anything that hasn't been parsed yet is a syntax error + // It seems that XBoard sometimes passes empty strings as arguments + // to PolyGlot. We ignore these. + + argc=1; + while((arg=argv[argc++])){ + if(!my_string_equal(arg,"")){ + my_fatal("main(): Incorrect use of option: \"%s\"\n",argv[argc-1]); + } + } + + // gui_init(GUI); + mainloop(); + return EXIT_SUCCESS; +} + +// polyglot_set_option() + +void polyglot_set_option(const char *name, const char *value){ // this must be cleaned up! + ini_t ini[1]; + int ret; + ini_init(ini); + my_log("POLYGLOT Setting PolyGlot option \"%s=%s\"\n",name,value); + if(my_string_case_equal(name,"Save")){ + ret=my_mkdir(option_get(Option,"SettingsDir")); + if(ret){ + my_log("POLYGLOT polyglot_set_option(): %s: %s\n", + option_get(Option,"SettingsDir"), + strerror(errno)); + } + make_ini(ini); + write_ini(option_get(Option,"SettingsFile"),ini); + return; + } +// if(my_string_equal(option_get(Option,name),value)){ +// my_log("Not setting PolyGlot option \"%s\" " +// "since it already as the correct value.\n", +// name); +// return; +// } + option_set(Option,name,value); + if(option_get_bool(Option,"Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){ + my_log("POLYGLOT *** SETTING BOOK ***\n"); + my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile")); + book_close(); + book_clear(); + book_open(option_get_string(Option,"BookFile")); + if(!book_is_open()){ + my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string(Option,"BookFile")); + } + }else if(option_get_bool(Option,"Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){ + my_log("POLYGLOT *** SWITCHING LOGFILE ***\n"); + my_log("POLYGLOT NEW LOGFILE \"%s\"\n",option_get_string(Option,"LogFile")); + my_log_close(); + my_log_open(option_get_string(Option,"LogFile")); + }else if(option_get_bool(Option,"UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(Engine,atoi(option_get_string(Option,"NiceValue"))); + }else if(my_string_case_equal(name,"Book") && !option_get_bool(Option,"Book")){ + book_close(); + book_clear(); + }else if(my_string_case_equal(name,"UseNice") && !option_get_bool(Option,"UseNice")){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(Engine,0); + }else if(my_string_case_equal(name,"Log") && !option_get_bool(Option,"Log")){ + my_log("POLYGLOT QUIT LOGGING\n"); + my_log_close(); + } +} + + + +// quit() + +void quit() { + my_log("POLYGLOT *** QUIT ***\n"); + if (Init && !Engine->pipex->quit_pending) { + stop_search(); + Engine->pipex->quit_pending=TRUE; + engine_send(Engine,"quit"); + engine_close(Engine); + + } + my_sleep(200); + my_log("POLYGLOT Calling exit\n"); + exit(EXIT_SUCCESS); +} + +// stop_search() + +static void stop_search() { + + if (Init && Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_log("POLYGLOT STOP SEARCH\n"); + + if (option_get_bool(Option,"SyncStop")) { + uci_send_stop_sync(Uci); + } else { + uci_send_stop(Uci); + } + } +} + + +// end of main.c + diff --git a/main.h b/main.h index f504f68..ecc078b 100644 --- a/main.h +++ b/main.h @@ -1,19 +1,19 @@ - -// main.h - -#ifndef MAIN_H -#define MAIN_H - -// includes - -#include "util.h" - -// functions - -extern void quit (); -extern void polyglot_set_option(const char *name, const char *value); - -#endif // !defined MAIN_H - -// end of main.h - + +// main.h + +#ifndef MAIN_H +#define MAIN_H + +// includes + +#include "util.h" + +// functions + +extern void quit (); +extern void polyglot_set_option(const char *name, const char *value); + +#endif // !defined MAIN_H + +// end of main.h + diff --git a/mainloop.c b/mainloop.c index 4f23279..ce51459 100644 --- a/mainloop.c +++ b/mainloop.c @@ -1,105 +1,101 @@ -// mainloop.c - -// constants - -#define StringSize ((int)4096) - -// includes - -#include -#include -#include -#include - -#include "main.h" -#include "engine.h" -#include "gui.h" -#include "option.h" -//#include "ini.h" -#include "xboard2uci.h" -#include "uci2uci.h" - -// prototypes - -static void mainloop_init (); -static void mainloop_wait_for_event (); -static void mainloop_engine_step(char * string); -static void mainloop_gui_step(char * string); - -// functions - -// mainloop_init() - -static void mainloop_init(){ - if(!option_get_bool(Option,"UCI")){ - xboard2uci_init(); // the default - } -} - -// mainloop_engine_step() - -static void mainloop_engine_step(char * string){ - if(option_get_bool(Option,"UCI")){ - uci2uci_engine_step(string); - }else{ - xboard2uci_engine_step(string); - } -} - -// mainloop_gui_step() - -static void mainloop_gui_step(char * string){ - if(option_get_bool(Option,"UCI")){ - uci2uci_gui_step(string); - }else if(my_string_equal(string,"uci")){ // mode auto detection - my_log("POLYGLOT *** Switching to UCI mode ***\n"); - option_set(Option,"UCI","true"); - uci2uci_gui_step(string); - }else{ - xboard2uci_gui_step(string); - } -} - -// mainloop() - -void mainloop() { - char string[StringSize]; - my_log("POLYGLOT *** Mainloop started ***\n"); - mainloop_init(); - while (!engine_eof(Engine)) { - // process buffered lines - while(TRUE){ - if(gui_get_non_blocking(GUI,string)){ - mainloop_gui_step(string); - }else if(!engine_eof(Engine) && - engine_get_non_blocking(Engine,string) ){ - mainloop_engine_step(string); - }else{ - break; - } - } - mainloop_wait_for_event(); - } - my_log("POLYGLOT *** Mainloop has ended ***\n"); - // This should be handled better. - engine_close(Engine); - my_log("POLYGLOT Calling exit\n"); - exit(EXIT_SUCCESS); - -} - - - - -// mainloop_wait_for_event() - -static void mainloop_wait_for_event(){ - pipex_t *pipex[3]; - pipex[0]=GUI->pipex; - pipex[1]=Engine->pipex; - pipex[2]=NULL; - pipex_wait_event(pipex); -} - - - +// mainloop.c + +// includes + +#include +#include +#include +#include + +#include "main.h" +#include "engine.h" +#include "gui.h" +#include "option.h" +//#include "ini.h" +#include "xboard2uci.h" +#include "uci2uci.h" + +// prototypes + +static void mainloop_init (); +static void mainloop_wait_for_event (); +static void mainloop_engine_step(char * string); +static void mainloop_gui_step(char * string); + +// functions + +// mainloop_init() + +static void mainloop_init(){ + if(!option_get_bool(Option,"UCI")){ + xboard2uci_init(); // the default + } +} + +// mainloop_engine_step() + +static void mainloop_engine_step(char * string){ + if(option_get_bool(Option,"UCI")){ + uci2uci_engine_step(string); + }else{ + xboard2uci_engine_step(string); + } +} + +// mainloop_gui_step() + +static void mainloop_gui_step(char * string){ + if(option_get_bool(Option,"UCI")){ + uci2uci_gui_step(string); + }else if(my_string_equal(string,"uci")){ // mode auto detection + my_log("POLYGLOT *** Switching to UCI mode ***\n"); + option_set(Option,"UCI","true"); + uci2uci_gui_step(string); + }else{ + xboard2uci_gui_step(string); + } +} + +// mainloop() + +void mainloop() { + char string[StringSize]; + my_log("POLYGLOT *** Mainloop started ***\n"); + mainloop_init(); + while (!engine_eof(Engine)) { + // process buffered lines + while(TRUE){ + if(gui_get_non_blocking(GUI,string)){ + mainloop_gui_step(string); + }else if(!engine_eof(Engine) && + engine_get_non_blocking(Engine,string) ){ + mainloop_engine_step(string); + }else{ + break; + } + } + mainloop_wait_for_event(); + } + my_log("POLYGLOT *** Mainloop has ended ***\n"); + // This should be handled better. + engine_close(Engine); + my_log("POLYGLOT Calling exit\n"); + exit(EXIT_SUCCESS); + +} + + + + +// mainloop_wait_for_event() + +static void mainloop_wait_for_event(){ + pipex_t *pipex[3]; + pipex[0]=GUI->pipex; + pipex[1]=Engine->pipex; + pipex[2]=NULL; + pipex_wait_event(pipex); +} + + + diff --git a/mainloop.h b/mainloop.h index 709b3c9..4cc1013 100644 --- a/mainloop.h +++ b/mainloop.h @@ -1,26 +1,26 @@ - -// mainloop.h - -#ifndef MAINLOOP_H -#define MAINLOOP_H - -// includes - -#include "util.h" -#include "uci2uci.h" - -// types - - - - - -// functions - -extern void mainloop (); - - -#endif // !defined MAINLOOP_H - -// end of mainloop.h - + +// mainloop.h + +#ifndef MAINLOOP_H +#define MAINLOOP_H + +// includes + +#include "util.h" +#include "uci2uci.h" + +// types + + + + + +// functions + +extern void mainloop (); + + +#endif // !defined MAINLOOP_H + +// end of mainloop.h + diff --git a/move.c b/move.c index 116f11d..90191f9 100644 --- a/move.c +++ b/move.c @@ -1,376 +1,376 @@ - -// move.c - -// includes - -#include -#include - -#include "attack.h" -#include "colour.h" -#include "list.h" -#include "move.h" -#include "move_do.h" -#include "move_gen.h" -#include "move_legal.h" -#include "option.h" -#include "piece.h" -#include "square.h" -#include "util.h" - -// "constants" - -static const uint8 PromotePiece[5] = { PieceNone64, Knight64, Bishop64, Rook64, Queen64 }; - -// functions - -// move_is_ok() - -bool move_is_ok(int move) { - - if (move < 0 || move >= 65536) return FALSE; - - if (move == MoveNone) return FALSE; - - return TRUE; -} - -// move_make() - -int move_make(int from, int to) { - - ASSERT(square_is_ok(from)); - ASSERT(square_is_ok(to)); - - return (square_to_64(from) << 6) | square_to_64(to); -} - -// move_make_flags() - -int move_make_flags(int from, int to, int flags) { - - ASSERT(square_is_ok(from)); - ASSERT(square_is_ok(to)); - ASSERT((flags&~0xF000)==0); - - ASSERT(to!=from); - - return (square_to_64(from) << 6) | square_to_64(to) | flags; -} - -// move_from() - -int move_from(int move) { - - int from_64; - - ASSERT(move_is_ok(move)); - - from_64 = (move >> 6) & 077; - - return square_from_64(from_64); -} - -// move_to() - -int move_to(int move) { - - int to_64; - - ASSERT(move_is_ok(move)); - - to_64 = move & 077; - - return square_from_64(to_64); -} - -// move_promote_hack() - -int move_promote_hack(int move) { - - int code; - - ASSERT(move_is_ok(move)); - - ASSERT(move_is_promote(move)); - - code = move >> 12; - ASSERT(code>=1&&code<=4); - - return PromotePiece[code]; -} - -// move_is_capture() - -bool move_is_capture(int move, const board_t * board) { - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - if (move_is_en_passant(move,board)) return TRUE; - if (board->square[move_to(move)] != Empty) return TRUE; - - return FALSE; -} - -// move_is_promote() - -bool move_is_promote(int move) { - - ASSERT(move_is_ok(move)); - - return (move & MoveFlags) != 0; -} - -// move_is_en_passant() - -bool move_is_en_passant(int move, const board_t * board) { - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - return piece_is_pawn(move_piece(move,board)) - && move_to(move) == board->ep_square; -} - -// move_is_castle() - -bool move_is_castle(int move, const board_t * board) { - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - return colour_equal(board->square[move_to(move)],board->turn); -} - -// move_piece() - -int move_piece(int move, const board_t * board) { - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - return board->square[move_from(move)]; -} - -// move_capture() - -int move_capture(int move, const board_t * board) { - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - if (move_is_en_passant(move,board)) { - return piece_pawn_opp(move_piece(move,board)); - } - - return board->square[move_to(move)]; -} - -// move_promote() - -int move_promote(int move, const board_t * board) { - - int code; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - if (move_is_promote(move)) { - code = move >> 12; - ASSERT(code>=1&&code<=4); - return PromotePiece[code] | board->turn; - } - - return Empty; -} - -// move_is_check() - -bool move_is_check(int move, const board_t * board) { - - board_t new_board[1]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - board_copy(new_board,board); - move_do(new_board,move); - ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); - - return board_is_check(new_board); -} - -// move_is_mate() - -bool move_is_mate(int move, const board_t * board) { - - board_t new_board[1]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - board_copy(new_board,board); - move_do(new_board,move); - ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); - - return board_is_mate(new_board); -} - -// move_to_can() - -bool move_to_can(int move, const board_t * board, char string[], int size) { - - int from, to; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=6); - - ASSERT(move_is_legal(move,board)); - - if (size < 6) return FALSE; - - // init - - from = move_from(move); - to = move_to(move); - - // king-slide castling - - if (move_is_castle(move,board) && !option_get_bool(Option,"Chess960")) { - if (FALSE) { - } else if (from == E1 && to == H1) { - to = G1; - } else if (from == E1 && to == A1) { - to = C1; - } else if (from == E8 && to == H8) { - to = G8; - } else if (from == E8 && to == A8) { - to = C8; - } - } - - // normal moves - - if (!square_to_string(from,&string[0],3)) ASSERT(FALSE); - if (!square_to_string(to,&string[2],3)) ASSERT(FALSE); - ASSERT(strlen(string)==4); - - // promotes - - if (move_is_promote(move)) { - string[4] = piece_to_char(move_promote_hack(move)|Black); // HACK: black => lower-case - string[5] = '\0'; - } - - // debug - - ASSERT(move_from_can(string,board)==move); - - return TRUE; -} - -// move_from_can() - -int move_from_can(const char string[], const board_t * board) { - - char tmp_string[256]; - int from, to; - int side; - int move; - - ASSERT(string!=NULL); - ASSERT(board_is_ok(board)); - - // from - - tmp_string[0] = string[0]; - tmp_string[1] = string[1]; - tmp_string[2] = '\0'; - - from = square_from_string(tmp_string); - if (from == SquareNone) return MoveNone; - - // to - - tmp_string[0] = string[2]; - tmp_string[1] = string[3]; - tmp_string[2] = '\0'; - - to = square_from_string(tmp_string); - if (to == SquareNone) return MoveNone; - - // convert "king slide" castling to KxR - - if (piece_is_king(board->square[from]) - && square_rank(to) == square_rank(from) - && abs(to-from) > 1) { - side = (to > from) ? SideH : SideA; - to = board->castle[board->turn][side]; - if (to == SquareNone) return MoveNone; - } - // move - - move = move_make(from,to); - - // promote - switch (string[4]) { - case '\0': // not a promotion - if (piece_is_pawn(board->square[from]) - && square_side_rank(to,board->turn) == Rank8 - && option_get_bool(Option,"PromoteWorkAround")) { - move |= MovePromoteQueen; - } - break; - case 'N': - case 'n': - move |= MovePromoteKnight; - break; - case 'B': - case 'b': - move |= MovePromoteBishop; - break; - case 'R': - case 'r': - move |= MovePromoteRook; - break; - case 'Q': - case 'q': - move |= MovePromoteQueen; - break; - default: - return MoveNone; - break; - } - // debug - - ASSERT(move_is_legal(move,board)); - return move; -} - -// move_order() - -int move_order(int move) { - - ASSERT(move_is_ok(move)); - - return ((move & 07777) << 3) | (move >> 12); // from, to, promote -} - -// move_disp() - -void move_disp(int move, const board_t * board) { - - char string[256]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - if (!move_to_can(move,board,string,256)) ASSERT(FALSE); - my_log("POLYGLOT %s\n",string); -} - -// end of move.cpp - + +// move.c + +// includes + +#include +#include + +#include "attack.h" +#include "colour.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "option.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// "constants" + +static const uint8 PromotePiece[5] = { PieceNone64, Knight64, Bishop64, Rook64, Queen64 }; + +// functions + +// move_is_ok() + +bool move_is_ok(int move) { + + if (move < 0 || move >= 65536) return FALSE; + + if (move == MoveNone) return FALSE; + + return TRUE; +} + +// move_make() + +int move_make(int from, int to) { + + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + + return (square_to_64(from) << 6) | square_to_64(to); +} + +// move_make_flags() + +int move_make_flags(int from, int to, int flags) { + + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + ASSERT((flags&~0xF000)==0); + + ASSERT(to!=from); + + return (square_to_64(from) << 6) | square_to_64(to) | flags; +} + +// move_from() + +int move_from(int move) { + + int from_64; + + ASSERT(move_is_ok(move)); + + from_64 = (move >> 6) & 077; + + return square_from_64(from_64); +} + +// move_to() + +int move_to(int move) { + + int to_64; + + ASSERT(move_is_ok(move)); + + to_64 = move & 077; + + return square_from_64(to_64); +} + +// move_promote_hack() + +int move_promote_hack(int move) { + + int code; + + ASSERT(move_is_ok(move)); + + ASSERT(move_is_promote(move)); + + code = move >> 12; + ASSERT(code>=1&&code<=4); + + return PromotePiece[code]; +} + +// move_is_capture() + +bool move_is_capture(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (move_is_en_passant(move,board)) return TRUE; + if (board->square[move_to(move)] != Empty) return TRUE; + + return FALSE; +} + +// move_is_promote() + +bool move_is_promote(int move) { + + ASSERT(move_is_ok(move)); + + return (move & MoveFlags) != 0; +} + +// move_is_en_passant() + +bool move_is_en_passant(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + return piece_is_pawn(move_piece(move,board)) + && move_to(move) == board->ep_square; +} + +// move_is_castle() + +bool move_is_castle(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + return colour_equal(board->square[move_to(move)],board->turn); +} + +// move_piece() + +int move_piece(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + return board->square[move_from(move)]; +} + +// move_capture() + +int move_capture(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (move_is_en_passant(move,board)) { + return piece_pawn_opp(move_piece(move,board)); + } + + return board->square[move_to(move)]; +} + +// move_promote() + +int move_promote(int move, const board_t * board) { + + int code; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (move_is_promote(move)) { + code = move >> 12; + ASSERT(code>=1&&code<=4); + return PromotePiece[code] | board->turn; + } + + return Empty; +} + +// move_is_check() + +bool move_is_check(int move, const board_t * board) { + + board_t new_board[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + board_copy(new_board,board); + move_do(new_board,move); + ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); + + return board_is_check(new_board); +} + +// move_is_mate() + +bool move_is_mate(int move, const board_t * board) { + + board_t new_board[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + board_copy(new_board,board); + move_do(new_board,move); + ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); + + return board_is_mate(new_board); +} + +// move_to_can() + +bool move_to_can(int move, const board_t * board, char string[], int size) { + + int from, to; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=6); + + ASSERT(move_is_legal(move,board)); + + if (size < 6) return FALSE; + + // init + + from = move_from(move); + to = move_to(move); + + // king-slide castling + + if (move_is_castle(move,board) && !option_get_bool(Option,"Chess960")) { + if (FALSE) { + } else if (from == E1 && to == H1) { + to = G1; + } else if (from == E1 && to == A1) { + to = C1; + } else if (from == E8 && to == H8) { + to = G8; + } else if (from == E8 && to == A8) { + to = C8; + } + } + + // normal moves + + if (!square_to_string(from,&string[0],3)) ASSERT(FALSE); + if (!square_to_string(to,&string[2],3)) ASSERT(FALSE); + ASSERT(strlen(string)==4); + + // promotes + + if (move_is_promote(move)) { + string[4] = piece_to_char(move_promote_hack(move)|Black); // HACK: black => lower-case + string[5] = '\0'; + } + + // debug + + ASSERT(move_from_can(string,board)==move); + + return TRUE; +} + +// move_from_can() + +int move_from_can(const char string[], const board_t * board) { + + char tmp_string[256]; + int from, to; + int side; + int move; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + // from + + tmp_string[0] = string[0]; + tmp_string[1] = string[1]; + tmp_string[2] = '\0'; + + from = square_from_string(tmp_string); + if (from == SquareNone) return MoveNone; + + // to + + tmp_string[0] = string[2]; + tmp_string[1] = string[3]; + tmp_string[2] = '\0'; + + to = square_from_string(tmp_string); + if (to == SquareNone) return MoveNone; + + // convert "king slide" castling to KxR + + if (piece_is_king(board->square[from]) + && square_rank(to) == square_rank(from) + && abs(to-from) > 1) { + side = (to > from) ? SideH : SideA; + to = board->castle[board->turn][side]; + if (to == SquareNone) return MoveNone; + } + // move + + move = move_make(from,to); + + // promote + switch (string[4]) { + case '\0': // not a promotion + if (piece_is_pawn(board->square[from]) + && square_side_rank(to,board->turn) == Rank8 + && option_get_bool(Option,"PromoteWorkAround")) { + move |= MovePromoteQueen; + } + break; + case 'N': + case 'n': + move |= MovePromoteKnight; + break; + case 'B': + case 'b': + move |= MovePromoteBishop; + break; + case 'R': + case 'r': + move |= MovePromoteRook; + break; + case 'Q': + case 'q': + move |= MovePromoteQueen; + break; + default: + return MoveNone; + break; + } + // debug + + ASSERT(move_is_legal(move,board)); + return move; +} + +// move_order() + +int move_order(int move) { + + ASSERT(move_is_ok(move)); + + return ((move & 07777) << 3) | (move >> 12); // from, to, promote +} + +// move_disp() + +void move_disp(int move, const board_t * board) { + + char string[256]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (!move_to_can(move,board,string,256)) ASSERT(FALSE); + my_log("POLYGLOT %s\n",string); +} + +// end of move.cpp + diff --git a/move.h b/move.h index c83f155..4d2fbc8 100644 --- a/move.h +++ b/move.h @@ -1,60 +1,60 @@ - -// move.h - -#ifndef MOVE_H -#define MOVE_H - -// includes - -#include "board.h" -#include "util.h" - -// defined - -// HACK: a1a1 cannot be a legal move -#define MoveNone (0) - -#define MovePromoteKnight (1 << 12) -#define MovePromoteBishop (2 << 12) -#define MovePromoteRook (3 << 12) -#define MovePromoteQueen (4 << 12) -#define MoveFlags (7 << 12) - -// types - -typedef uint16 move_t; - -// functions - -extern bool move_is_ok (int move); - -extern int move_make (int from, int to); -extern int move_make_flags (int from, int to, int flags); - -extern int move_from (int move); -extern int move_to (int move); -extern int move_promote_hack (int move); - -extern bool move_is_capture (int move, const board_t * board); -extern bool move_is_promote (int move); -extern bool move_is_en_passant (int move, const board_t * board); -extern bool move_is_castle (int move, const board_t * board); - -extern int move_piece (int move, const board_t * board); -extern int move_capture (int move, const board_t * board); -extern int move_promote (int move, const board_t * board); - -extern bool move_is_check (int move, const board_t * board); -extern bool move_is_mate (int move, const board_t * board); - -extern int move_order (int move); - -extern bool move_to_can (int move, const board_t * board, char string[], int size); -extern int move_from_can (const char string[], const board_t * board); - -extern void move_disp (int move, const board_t * board); - -#endif // !defined MOVE_H - -// end of move.h - + +// move.h + +#ifndef MOVE_H +#define MOVE_H + +// includes + +#include "board.h" +#include "util.h" + +// defined + +// HACK: a1a1 cannot be a legal move +#define MoveNone (0) + +#define MovePromoteKnight (1 << 12) +#define MovePromoteBishop (2 << 12) +#define MovePromoteRook (3 << 12) +#define MovePromoteQueen (4 << 12) +#define MoveFlags (7 << 12) + +// types + +typedef uint16 move_t; + +// functions + +extern bool move_is_ok (int move); + +extern int move_make (int from, int to); +extern int move_make_flags (int from, int to, int flags); + +extern int move_from (int move); +extern int move_to (int move); +extern int move_promote_hack (int move); + +extern bool move_is_capture (int move, const board_t * board); +extern bool move_is_promote (int move); +extern bool move_is_en_passant (int move, const board_t * board); +extern bool move_is_castle (int move, const board_t * board); + +extern int move_piece (int move, const board_t * board); +extern int move_capture (int move, const board_t * board); +extern int move_promote (int move, const board_t * board); + +extern bool move_is_check (int move, const board_t * board); +extern bool move_is_mate (int move, const board_t * board); + +extern int move_order (int move); + +extern bool move_to_can (int move, const board_t * board, char string[], int size); +extern int move_from_can (const char string[], const board_t * board); + +extern void move_disp (int move, const board_t * board); + +#endif // !defined MOVE_H + +// end of move.h + diff --git a/move_do.c b/move_do.c index 8c00687..ac17161 100644 --- a/move_do.c +++ b/move_do.c @@ -1,363 +1,363 @@ - -// move_do.c - -// includes - -#include - -#include "board.h" -#include "colour.h" -#include "hash.h" -#include "move.h" -#include "move_do.h" -#include "move_legal.h" -#include "piece.h" -#include "random.h" -#include "util.h" - -// prototypes - -static void square_clear (board_t * board, int square, int piece); -static void square_set (board_t * board, int square, int piece, int pos); -static void square_move (board_t * board, int from, int to, int piece); - -// functions - -// move_do() - -void move_do(board_t * board, int move) { - - int me, opp; - int from, to; - int piece, pos, capture; - int old_flags, new_flags; - int sq, ep_square; - int pawn; - - ASSERT(board_is_ok(board)); - ASSERT(move_is_ok(move)); - - ASSERT(move_is_pseudo(move,board)); - - // init - - me = board->turn; - opp = colour_opp(me); - - from = move_from(move); - to = move_to(move); - - piece = board->square[from]; - ASSERT(colour_equal(piece,me)); - - pos = board->pos[from]; - ASSERT(pos>=0); - - // update turn - - board->turn = opp; - board->key ^= random_64(RandomTurn); - - // update castling rights - - old_flags = board_flags(board); - - if (piece_is_king(piece)) { - board->castle[me][SideH] = SquareNone; - board->castle[me][SideA] = SquareNone; - } - - if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone; - if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone; - - if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone; - if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone; - - new_flags = board_flags(board); - - board->key ^= hash_castle_key(new_flags^old_flags); // HACK - - // update en-passant square - - ep_square = sq = board->ep_square; - if (sq != SquareNone) { - board->key ^= random_64(RandomEnPassant+square_file(sq)); - board->ep_square = SquareNone; - } - - if (piece_is_pawn(piece) && abs(to-from) == 32) { - pawn = piece_make_pawn(opp); - if (board->square[to-1] == pawn || board->square[to+1] == pawn) { - board->ep_square = sq = (from + to) / 2; - board->key ^= random_64(RandomEnPassant+square_file(sq)); - } - } - - // update ply number (captures are handled later) - - board->ply_nb++; - if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion - - // update move number - - if (me == Black) board->move_nb++; - - // castle - - if (colour_equal(board->square[to],me)) { - - int rank; - int king_from, king_to; - int rook_from, rook_to; - int rook; - - rank = colour_is_white(me) ? Rank1 : Rank8; - - king_from = from; - rook_from = to; - - if (to > from) { // h side - king_to = square_make(FileG,rank); - rook_to = square_make(FileF,rank); - } else { // a side - king_to = square_make(FileC,rank); - rook_to = square_make(FileD,rank); - } - - // remove the rook - - pos = board->pos[rook_from]; - ASSERT(pos>=0); - - rook = Rook64 | me; // HACK - - square_clear(board,rook_from,rook); - - // move the king - - square_move(board,king_from,king_to,piece); - - // put the rook back - - square_set(board,rook_to,rook,pos); - - ASSERT(board->key==hash_key(board)); - - return; - } - - // remove the captured piece - - if (piece_is_pawn(piece) && to == ep_square) { - - // en-passant capture - - sq = square_ep_dual(to); - capture = board->square[sq]; - ASSERT(capture==piece_make_pawn(opp)); - - square_clear(board,sq,capture); - - board->ply_nb = 0; // conversion - - } else { - - capture = board->square[to]; - - if (capture != Empty) { - - // normal capture - - ASSERT(colour_equal(capture,opp)); - ASSERT(!piece_is_king(capture)); - - square_clear(board,to,capture); - - board->ply_nb = 0; // conversion - } - } - - // move the piece - - if (move_is_promote(move)) { - - // promote - - square_clear(board,from,piece); - piece = move_promote_hack(move) | me; // HACK - square_set(board,to,piece,pos); - - } else { - - // normal move - - square_move(board,from,to,piece); - } - - ASSERT(board->key==hash_key(board)); -} - -// square_clear() - -static void square_clear(board_t * board, int square, int piece) { - - int pos, piece_12, colour; - int sq, size; - - ASSERT(board!=NULL); - ASSERT(square_is_ok(square)); - ASSERT(piece_is_ok(piece)); - - // init - - pos = board->pos[square]; - ASSERT(pos>=0); - - colour = piece_colour(piece); - piece_12 = piece_to_12(piece); - - // square - - ASSERT(board->square[square]==piece); - board->square[square] = Empty; - - ASSERT(board->pos[square]==pos); - board->pos[square] = -1; // not needed - - // piece list - - ASSERT(board->list_size[colour]>=2); - size = --board->list_size[colour]; - ASSERT(pos<=size); - - if (pos != size) { - - sq = board->list[colour][size]; - ASSERT(square_is_ok(sq)); - ASSERT(sq!=square); - - ASSERT(board->pos[sq]==size); - board->pos[sq] = pos; - - ASSERT(board->list[colour][pos]==square); - board->list[colour][pos] = sq; - } - - board->list[colour][size] = SquareNone; - - // material - - ASSERT(board->number[piece_12]>=1); - board->number[piece_12]--; - - // hash key - - board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); -} - -// square_set() - -static void square_set(board_t * board, int square, int piece, int pos) { - - int piece_12, colour; - int sq, size; - - ASSERT(board!=NULL); - ASSERT(square_is_ok(square)); - ASSERT(piece_is_ok(piece)); - ASSERT(pos>=0); - - // init - - colour = piece_colour(piece); - piece_12 = piece_to_12(piece); - - // square - - ASSERT(board->square[square]==Empty); - board->square[square] = piece; - - ASSERT(board->pos[square]==-1); - board->pos[square] = pos; - - // piece list - - size = board->list_size[colour]++; - ASSERT(board->list[colour][size]==SquareNone); - ASSERT(pos<=size); - - if (pos != size) { - - sq = board->list[colour][pos]; - ASSERT(square_is_ok(sq)); - ASSERT(sq!=square); - - ASSERT(board->pos[sq]==pos); - board->pos[sq] = size; - - ASSERT(board->list[colour][size]==SquareNone); - board->list[colour][size] = sq; - } - - board->list[colour][pos] = square; - - // material - - ASSERT(board->number[piece_12]<=8); - board->number[piece_12]++; - - // hash key - - board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); -} - -// square_move() - -static void square_move(board_t * board, int from, int to, int piece) { - - int colour, pos; - int piece_index; - - ASSERT(board!=NULL); - ASSERT(square_is_ok(from)); - ASSERT(square_is_ok(to)); - ASSERT(piece_is_ok(piece)); - - // init - - colour = piece_colour(piece); - - pos = board->pos[from]; - ASSERT(pos>=0); - - // from - - ASSERT(board->square[from]==piece); - board->square[from] = Empty; - - ASSERT(board->pos[from]==pos); - board->pos[from] = -1; // not needed - - // to - - ASSERT(board->square[to]==Empty); - board->square[to] = piece; - - ASSERT(board->pos[to]==-1); - board->pos[to] = pos; - - // piece list - - ASSERT(board->list[colour][pos]==from); - board->list[colour][pos] = to; - - // hash key - - piece_index = RandomPiece + piece_to_12(piece) * 64; - - board->key ^= random_64(piece_index+square_to_64(from)) - ^ random_64(piece_index+square_to_64(to)); -} - -// end of move_do.cpp - + +// move_do.c + +// includes + +#include + +#include "board.h" +#include "colour.h" +#include "hash.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "piece.h" +#include "random.h" +#include "util.h" + +// prototypes + +static void square_clear (board_t * board, int square, int piece); +static void square_set (board_t * board, int square, int piece, int pos); +static void square_move (board_t * board, int from, int to, int piece); + +// functions + +// move_do() + +void move_do(board_t * board, int move) { + + int me, opp; + int from, to; + int piece, pos, capture; + int old_flags, new_flags; + int sq, ep_square; + int pawn; + + ASSERT(board_is_ok(board)); + ASSERT(move_is_ok(move)); + + ASSERT(move_is_pseudo(move,board)); + + // init + + me = board->turn; + opp = colour_opp(me); + + from = move_from(move); + to = move_to(move); + + piece = board->square[from]; + ASSERT(colour_equal(piece,me)); + + pos = board->pos[from]; + ASSERT(pos>=0); + + // update turn + + board->turn = opp; + board->key ^= random_64(RandomTurn); + + // update castling rights + + old_flags = board_flags(board); + + if (piece_is_king(piece)) { + board->castle[me][SideH] = SquareNone; + board->castle[me][SideA] = SquareNone; + } + + if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone; + if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone; + + if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone; + if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone; + + new_flags = board_flags(board); + + board->key ^= hash_castle_key(new_flags^old_flags); // HACK + + // update en-passant square + + ep_square = sq = board->ep_square; + if (sq != SquareNone) { + board->key ^= random_64(RandomEnPassant+square_file(sq)); + board->ep_square = SquareNone; + } + + if (piece_is_pawn(piece) && abs(to-from) == 32) { + pawn = piece_make_pawn(opp); + if (board->square[to-1] == pawn || board->square[to+1] == pawn) { + board->ep_square = sq = (from + to) / 2; + board->key ^= random_64(RandomEnPassant+square_file(sq)); + } + } + + // update ply number (captures are handled later) + + board->ply_nb++; + if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion + + // update move number + + if (me == Black) board->move_nb++; + + // castle + + if (colour_equal(board->square[to],me)) { + + int rank; + int king_from, king_to; + int rook_from, rook_to; + int rook; + + rank = colour_is_white(me) ? Rank1 : Rank8; + + king_from = from; + rook_from = to; + + if (to > from) { // h side + king_to = square_make(FileG,rank); + rook_to = square_make(FileF,rank); + } else { // a side + king_to = square_make(FileC,rank); + rook_to = square_make(FileD,rank); + } + + // remove the rook + + pos = board->pos[rook_from]; + ASSERT(pos>=0); + + rook = Rook64 | me; // HACK + + square_clear(board,rook_from,rook); + + // move the king + + square_move(board,king_from,king_to,piece); + + // put the rook back + + square_set(board,rook_to,rook,pos); + + ASSERT(board->key==hash_key(board)); + + return; + } + + // remove the captured piece + + if (piece_is_pawn(piece) && to == ep_square) { + + // en-passant capture + + sq = square_ep_dual(to); + capture = board->square[sq]; + ASSERT(capture==piece_make_pawn(opp)); + + square_clear(board,sq,capture); + + board->ply_nb = 0; // conversion + + } else { + + capture = board->square[to]; + + if (capture != Empty) { + + // normal capture + + ASSERT(colour_equal(capture,opp)); + ASSERT(!piece_is_king(capture)); + + square_clear(board,to,capture); + + board->ply_nb = 0; // conversion + } + } + + // move the piece + + if (move_is_promote(move)) { + + // promote + + square_clear(board,from,piece); + piece = move_promote_hack(move) | me; // HACK + square_set(board,to,piece,pos); + + } else { + + // normal move + + square_move(board,from,to,piece); + } + + ASSERT(board->key==hash_key(board)); +} + +// square_clear() + +static void square_clear(board_t * board, int square, int piece) { + + int pos, piece_12, colour; + int sq, size; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(square)); + ASSERT(piece_is_ok(piece)); + + // init + + pos = board->pos[square]; + ASSERT(pos>=0); + + colour = piece_colour(piece); + piece_12 = piece_to_12(piece); + + // square + + ASSERT(board->square[square]==piece); + board->square[square] = Empty; + + ASSERT(board->pos[square]==pos); + board->pos[square] = -1; // not needed + + // piece list + + ASSERT(board->list_size[colour]>=2); + size = --board->list_size[colour]; + ASSERT(pos<=size); + + if (pos != size) { + + sq = board->list[colour][size]; + ASSERT(square_is_ok(sq)); + ASSERT(sq!=square); + + ASSERT(board->pos[sq]==size); + board->pos[sq] = pos; + + ASSERT(board->list[colour][pos]==square); + board->list[colour][pos] = sq; + } + + board->list[colour][size] = SquareNone; + + // material + + ASSERT(board->number[piece_12]>=1); + board->number[piece_12]--; + + // hash key + + board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); +} + +// square_set() + +static void square_set(board_t * board, int square, int piece, int pos) { + + int piece_12, colour; + int sq, size; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(square)); + ASSERT(piece_is_ok(piece)); + ASSERT(pos>=0); + + // init + + colour = piece_colour(piece); + piece_12 = piece_to_12(piece); + + // square + + ASSERT(board->square[square]==Empty); + board->square[square] = piece; + + ASSERT(board->pos[square]==-1); + board->pos[square] = pos; + + // piece list + + size = board->list_size[colour]++; + ASSERT(board->list[colour][size]==SquareNone); + ASSERT(pos<=size); + + if (pos != size) { + + sq = board->list[colour][pos]; + ASSERT(square_is_ok(sq)); + ASSERT(sq!=square); + + ASSERT(board->pos[sq]==pos); + board->pos[sq] = size; + + ASSERT(board->list[colour][size]==SquareNone); + board->list[colour][size] = sq; + } + + board->list[colour][pos] = square; + + // material + + ASSERT(board->number[piece_12]<=8); + board->number[piece_12]++; + + // hash key + + board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); +} + +// square_move() + +static void square_move(board_t * board, int from, int to, int piece) { + + int colour, pos; + int piece_index; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + ASSERT(piece_is_ok(piece)); + + // init + + colour = piece_colour(piece); + + pos = board->pos[from]; + ASSERT(pos>=0); + + // from + + ASSERT(board->square[from]==piece); + board->square[from] = Empty; + + ASSERT(board->pos[from]==pos); + board->pos[from] = -1; // not needed + + // to + + ASSERT(board->square[to]==Empty); + board->square[to] = piece; + + ASSERT(board->pos[to]==-1); + board->pos[to] = pos; + + // piece list + + ASSERT(board->list[colour][pos]==from); + board->list[colour][pos] = to; + + // hash key + + piece_index = RandomPiece + piece_to_12(piece) * 64; + + board->key ^= random_64(piece_index+square_to_64(from)) + ^ random_64(piece_index+square_to_64(to)); +} + +// end of move_do.cpp + diff --git a/move_do.h b/move_do.h index 5954986..d77ea81 100644 --- a/move_do.h +++ b/move_do.h @@ -1,19 +1,19 @@ - -// move_do.h - -#ifndef MOVE_DO_H -#define MOVE_DO_H - -// includes - -#include "board.h" -#include "util.h" - -// functions - -extern void move_do (board_t * board, int move); - -#endif // !defined MOVE_DO_H - -// end of move_do.h - + +// move_do.h + +#ifndef MOVE_DO_H +#define MOVE_DO_H + +// includes + +#include "board.h" +#include "util.h" + +// functions + +extern void move_do (board_t * board, int move); + +#endif // !defined MOVE_DO_H + +// end of move_do.h + diff --git a/move_gen.c b/move_gen.c index 2d45564..6ebaf42 100644 --- a/move_gen.c +++ b/move_gen.c @@ -1,328 +1,328 @@ - -// move_gen.c - -// includes - -#include "attack.h" -#include "board.h" -#include "colour.h" -#include "list.h" -#include "move.h" -#include "move_gen.h" -#include "move_legal.h" -#include "piece.h" -#include "util.h" - -// prototypes - -static void add_all_moves (list_t * list, const board_t * board); -static void add_castle_moves (list_t * list, const board_t * board); - -static void add_pawn_move (list_t * list, int from, int to); - -// functions - -// gen_legal_moves() - -void gen_legal_moves(list_t * list, const board_t * board) { - - ASSERT(list!=NULL); - ASSERT(board_is_ok(board)); - - gen_moves(list,board); - filter_legal(list,board); -} - -// gen_moves() - -void gen_moves(list_t * list, const board_t * board) { - - ASSERT(list!=NULL); - ASSERT(board_is_ok(board)); - - list_clear(list); - - add_all_moves(list,board); - if (!is_in_check(board,board->turn)) add_castle_moves(list,board); -} - -// add_all_moves() - -static void add_all_moves(list_t * list, const board_t * board) { - - int me, opp; - const uint8 * ptr; - const sint8 * ptr_inc; - int from, to; - int inc; - int piece, capture; - - ASSERT(list_is_ok(list)); - ASSERT(board_is_ok(board)); - - me = board->turn; - opp = colour_opp(me); - - for (ptr = board->list[me]; (from=*ptr) != SquareNone; ptr++) { - - piece = board->square[from]; - ASSERT(colour_equal(piece,me)); - - switch (piece_type(piece)) { - - case WhitePawn64: - - to = from + 15; - if (to == board->ep_square || colour_equal(board->square[to],opp)) { - add_pawn_move(list,from,to); - } - - to = from + 17; - if (to == board->ep_square || colour_equal(board->square[to],opp)) { - add_pawn_move(list,from,to); - } - - to = from + 16; - if (board->square[to] == Empty) { - add_pawn_move(list,from,to); - if (square_rank(from) == Rank2) { - to = from + 32; - if (board->square[to] == Empty) { - ASSERT(!square_is_promote(to)); - list_add(list,move_make(from,to)); - } - } - } - - break; - - case BlackPawn64: - - to = from - 17; - if (to == board->ep_square || colour_equal(board->square[to],opp)) { - add_pawn_move(list,from,to); - } - - to = from - 15; - if (to == board->ep_square || colour_equal(board->square[to],opp)) { - add_pawn_move(list,from,to); - } - - to = from - 16; - if (board->square[to] == Empty) { - add_pawn_move(list,from,to); - if (square_rank(from) == Rank7) { - to = from - 32; - if (board->square[to] == Empty) { - ASSERT(!square_is_promote(to)); - list_add(list,move_make(from,to)); - } - } - } - - break; - - case Knight64: - - for (ptr_inc = KnightInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { - to = from + inc; - capture = board->square[to]; - if (capture == Empty || colour_equal(capture,opp)) { - list_add(list,move_make(from,to)); - } - } - - break; - - case Bishop64: - - for (ptr_inc = BishopInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { - for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { - list_add(list,move_make(from,to)); - } - if (colour_equal(capture,opp)) { - list_add(list,move_make(from,to)); - } - } - - break; - - case Rook64: - - for (ptr_inc = RookInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { - for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { - list_add(list,move_make(from,to)); - } - if (colour_equal(capture,opp)) { - list_add(list,move_make(from,to)); - } - } - - break; - - case Queen64: - - for (ptr_inc = QueenInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { - for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { - list_add(list,move_make(from,to)); - } - if (colour_equal(capture,opp)) { - list_add(list,move_make(from,to)); - } - } - - break; - - case King64: - - for (ptr_inc = KingInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { - to = from + inc; - capture = board->square[to]; - if (capture == Empty || colour_equal(capture,opp)) { - list_add(list,move_make(from,to)); - } - } - - break; - - default: - - ASSERT(FALSE); - break; - } - } -} - -// add_castle_moves() - -static void add_castle_moves(list_t * list, const board_t * board) { - - int me, opp; - int rank; - int king_from, king_to; - int rook_from, rook_to; - bool legal; - int inc; - int sq; - - ASSERT(list_is_ok(list)); - ASSERT(board_is_ok(board)); - - ASSERT(!is_in_check(board,board->turn)); - - me = board->turn; - opp = colour_opp(me); - - rank = colour_is_white(me) ? Rank1 : Rank8; - - // h-side castling - - if (board->castle[me][SideH] != SquareNone) { - - king_from = king_pos(board,me); - king_to = square_make(FileG,rank); - rook_from = board->castle[me][SideH]; - rook_to = square_make(FileF,rank); - - ASSERT(square_rank(king_from)==rank); - ASSERT(square_rank(rook_from)==rank); - ASSERT(board->square[king_from]==(King64|me)); // HACK - ASSERT(board->square[rook_from]==(Rook64|me)); // HACK - ASSERT(rook_from>king_from); - - legal = TRUE; - - if (king_to != king_from) { - - inc = (king_to > king_from) ? +1 : -1; - - for (sq = king_from+inc; TRUE; sq += inc) { - - if (sq != rook_from && board->square[sq] != Empty) legal = FALSE; - if (is_attacked(board,sq,opp)) legal = FALSE; - - if (sq == king_to) break; - } - } - - if (rook_to != rook_from) { - - inc = (rook_to > rook_from) ? +1 : -1; - - for (sq = rook_from+inc; TRUE; sq += inc) { - if (sq != king_from && board->square[sq] != Empty) legal = FALSE; - if (sq == rook_to) break; - } - } - - if (legal) list_add(list,move_make(king_from,rook_from)); - } - - // a-side castling - - if (board->castle[me][SideA] != SquareNone) { - - king_from = king_pos(board,me); - king_to = square_make(FileC,rank); - rook_from = board->castle[me][SideA]; - rook_to = square_make(FileD,rank); - - ASSERT(square_rank(king_from)==rank); - ASSERT(square_rank(rook_from)==rank); - ASSERT(board->square[king_from]==(King64|me)); // HACK - ASSERT(board->square[rook_from]==(Rook64|me)); // HACK - ASSERT(rook_from king_from) ? +1 : -1; - - for (sq = king_from+inc; TRUE; sq += inc) { - - if (sq != rook_from && board->square[sq] != Empty) legal = FALSE; - if (is_attacked(board,sq,opp)) legal = FALSE; - - if (sq == king_to) break; - } - } - - if (rook_to != rook_from) { - - inc = (rook_to > rook_from) ? +1 : -1; - - for (sq = rook_from+inc; TRUE; sq += inc) { - if (sq != king_from && board->square[sq] != Empty) legal = FALSE; - if (sq == rook_to) break; - } - } - - if (legal) list_add(list,move_make(king_from,rook_from)); - } -} - -// add_pawn_move() - -static void add_pawn_move(list_t * list, int from, int to) { - - int move; - - ASSERT(list_is_ok(list)); - ASSERT(square_is_ok(from)); - ASSERT(square_is_ok(to)); - - move = move_make(from,to); - - if (square_is_promote(to)) { - list_add(list,move|MovePromoteKnight); - list_add(list,move|MovePromoteBishop); - list_add(list,move|MovePromoteRook); - list_add(list,move|MovePromoteQueen); - } else { - list_add(list,move); - } -} - -// end of move_gen.cpp - + +// move_gen.c + +// includes + +#include "attack.h" +#include "board.h" +#include "colour.h" +#include "list.h" +#include "move.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "util.h" + +// prototypes + +static void add_all_moves (list_t * list, const board_t * board); +static void add_castle_moves (list_t * list, const board_t * board); + +static void add_pawn_move (list_t * list, int from, int to); + +// functions + +// gen_legal_moves() + +void gen_legal_moves(list_t * list, const board_t * board) { + + ASSERT(list!=NULL); + ASSERT(board_is_ok(board)); + + gen_moves(list,board); + filter_legal(list,board); +} + +// gen_moves() + +void gen_moves(list_t * list, const board_t * board) { + + ASSERT(list!=NULL); + ASSERT(board_is_ok(board)); + + list_clear(list); + + add_all_moves(list,board); + if (!is_in_check(board,board->turn)) add_castle_moves(list,board); +} + +// add_all_moves() + +static void add_all_moves(list_t * list, const board_t * board) { + + int me, opp; + const uint8 * ptr; + const sint8 * ptr_inc; + int from, to; + int inc; + int piece, capture; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + me = board->turn; + opp = colour_opp(me); + + for (ptr = board->list[me]; (from=*ptr) != SquareNone; ptr++) { + + piece = board->square[from]; + ASSERT(colour_equal(piece,me)); + + switch (piece_type(piece)) { + + case WhitePawn64: + + to = from + 15; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from + 17; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from + 16; + if (board->square[to] == Empty) { + add_pawn_move(list,from,to); + if (square_rank(from) == Rank2) { + to = from + 32; + if (board->square[to] == Empty) { + ASSERT(!square_is_promote(to)); + list_add(list,move_make(from,to)); + } + } + } + + break; + + case BlackPawn64: + + to = from - 17; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from - 15; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from - 16; + if (board->square[to] == Empty) { + add_pawn_move(list,from,to); + if (square_rank(from) == Rank7) { + to = from - 32; + if (board->square[to] == Empty) { + ASSERT(!square_is_promote(to)); + list_add(list,move_make(from,to)); + } + } + } + + break; + + case Knight64: + + for (ptr_inc = KnightInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + to = from + inc; + capture = board->square[to]; + if (capture == Empty || colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case Bishop64: + + for (ptr_inc = BishopInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { + list_add(list,move_make(from,to)); + } + if (colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case Rook64: + + for (ptr_inc = RookInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { + list_add(list,move_make(from,to)); + } + if (colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case Queen64: + + for (ptr_inc = QueenInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { + list_add(list,move_make(from,to)); + } + if (colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case King64: + + for (ptr_inc = KingInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + to = from + inc; + capture = board->square[to]; + if (capture == Empty || colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + default: + + ASSERT(FALSE); + break; + } + } +} + +// add_castle_moves() + +static void add_castle_moves(list_t * list, const board_t * board) { + + int me, opp; + int rank; + int king_from, king_to; + int rook_from, rook_to; + bool legal; + int inc; + int sq; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + ASSERT(!is_in_check(board,board->turn)); + + me = board->turn; + opp = colour_opp(me); + + rank = colour_is_white(me) ? Rank1 : Rank8; + + // h-side castling + + if (board->castle[me][SideH] != SquareNone) { + + king_from = king_pos(board,me); + king_to = square_make(FileG,rank); + rook_from = board->castle[me][SideH]; + rook_to = square_make(FileF,rank); + + ASSERT(square_rank(king_from)==rank); + ASSERT(square_rank(rook_from)==rank); + ASSERT(board->square[king_from]==(King64|me)); // HACK + ASSERT(board->square[rook_from]==(Rook64|me)); // HACK + ASSERT(rook_from>king_from); + + legal = TRUE; + + if (king_to != king_from) { + + inc = (king_to > king_from) ? +1 : -1; + + for (sq = king_from+inc; TRUE; sq += inc) { + + if (sq != rook_from && board->square[sq] != Empty) legal = FALSE; + if (is_attacked(board,sq,opp)) legal = FALSE; + + if (sq == king_to) break; + } + } + + if (rook_to != rook_from) { + + inc = (rook_to > rook_from) ? +1 : -1; + + for (sq = rook_from+inc; TRUE; sq += inc) { + if (sq != king_from && board->square[sq] != Empty) legal = FALSE; + if (sq == rook_to) break; + } + } + + if (legal) list_add(list,move_make(king_from,rook_from)); + } + + // a-side castling + + if (board->castle[me][SideA] != SquareNone) { + + king_from = king_pos(board,me); + king_to = square_make(FileC,rank); + rook_from = board->castle[me][SideA]; + rook_to = square_make(FileD,rank); + + ASSERT(square_rank(king_from)==rank); + ASSERT(square_rank(rook_from)==rank); + ASSERT(board->square[king_from]==(King64|me)); // HACK + ASSERT(board->square[rook_from]==(Rook64|me)); // HACK + ASSERT(rook_from king_from) ? +1 : -1; + + for (sq = king_from+inc; TRUE; sq += inc) { + + if (sq != rook_from && board->square[sq] != Empty) legal = FALSE; + if (is_attacked(board,sq,opp)) legal = FALSE; + + if (sq == king_to) break; + } + } + + if (rook_to != rook_from) { + + inc = (rook_to > rook_from) ? +1 : -1; + + for (sq = rook_from+inc; TRUE; sq += inc) { + if (sq != king_from && board->square[sq] != Empty) legal = FALSE; + if (sq == rook_to) break; + } + } + + if (legal) list_add(list,move_make(king_from,rook_from)); + } +} + +// add_pawn_move() + +static void add_pawn_move(list_t * list, int from, int to) { + + int move; + + ASSERT(list_is_ok(list)); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + + move = move_make(from,to); + + if (square_is_promote(to)) { + list_add(list,move|MovePromoteKnight); + list_add(list,move|MovePromoteBishop); + list_add(list,move|MovePromoteRook); + list_add(list,move|MovePromoteQueen); + } else { + list_add(list,move); + } +} + +// end of move_gen.cpp + diff --git a/move_gen.h b/move_gen.h index b4dc1f2..c62e2c4 100644 --- a/move_gen.h +++ b/move_gen.h @@ -1,21 +1,21 @@ - -// move_gen.h - -#ifndef MOVE_GEN_H -#define MOVE_GEN_H - -// includes - -#include "board.h" -#include "list.h" -#include "util.h" - -// functions - -extern void gen_legal_moves (list_t * list, const board_t * board); -extern void gen_moves (list_t * list, const board_t * board); - -#endif // !defined MOVE_GEN_H - -// end of move_gen.h - + +// move_gen.h + +#ifndef MOVE_GEN_H +#define MOVE_GEN_H + +// includes + +#include "board.h" +#include "list.h" +#include "util.h" + +// functions + +extern void gen_legal_moves (list_t * list, const board_t * board); +extern void gen_moves (list_t * list, const board_t * board); + +#endif // !defined MOVE_GEN_H + +// end of move_gen.h + diff --git a/move_legal.c b/move_legal.c index ecf3fd2..cf19baf 100644 --- a/move_legal.c +++ b/move_legal.c @@ -1,115 +1,115 @@ - -// move_legal.c - -// includes - -#include "attack.h" -#include "colour.h" -#include "fen.h" -#include "list.h" -#include "move.h" -#include "move_do.h" -#include "move_gen.h" -#include "move_legal.h" -#include "piece.h" -#include "square.h" -#include "util.h" - -// prototypes - -static bool move_is_legal_debug (int move, const board_t * board); - -// functions - -// move_is_pseudo() - -bool move_is_pseudo(int move, const board_t * board) { - - list_t list[1]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - gen_moves(list,board); - - return list_contain(list,move); -} - -// pseudo_is_legal() - -bool pseudo_is_legal(int move, const board_t * board) { - - board_t new_board[1]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - ASSERT(move_is_pseudo(move,board)); - - board_copy(new_board,board); - move_do(new_board,move); - - return !is_in_check(new_board,colour_opp(new_board->turn)); -} - -// move_is_legal() - -bool move_is_legal(int move, const board_t * board) { - - bool legal; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board); - ASSERT(legal==move_is_legal_debug(move,board)); - - return legal; -} - -// filter_legal() - -void filter_legal(list_t * list, const board_t * board) { - - int pos; - int i, move, value; - - ASSERT(list_is_ok(list)); - ASSERT(board_is_ok(board)); - - pos = 0; - - for (i = 0; i < list_size(list); i++) { - - ASSERT(pos>=0&&pos<=i); - - move = list_move(list,i); - value = list_value(list,i); - - if (pseudo_is_legal(move,board)) { - list->move[pos] = move; - list->value[pos] = value; - pos++; - } - } - - ASSERT(pos>=0&&pos<=list_size(list)); - list->size = pos; -} - -// move_is_legal_debug() - -static bool move_is_legal_debug(int move, const board_t * board) { - - list_t list[1]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - - gen_legal_moves(list,board); - - return list_contain(list,move); -} - -// end of move_legal.cpp - + +// move_legal.c + +// includes + +#include "attack.h" +#include "colour.h" +#include "fen.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// prototypes + +static bool move_is_legal_debug (int move, const board_t * board); + +// functions + +// move_is_pseudo() + +bool move_is_pseudo(int move, const board_t * board) { + + list_t list[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + gen_moves(list,board); + + return list_contain(list,move); +} + +// pseudo_is_legal() + +bool pseudo_is_legal(int move, const board_t * board) { + + board_t new_board[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + ASSERT(move_is_pseudo(move,board)); + + board_copy(new_board,board); + move_do(new_board,move); + + return !is_in_check(new_board,colour_opp(new_board->turn)); +} + +// move_is_legal() + +bool move_is_legal(int move, const board_t * board) { + + bool legal; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board); + ASSERT(legal==move_is_legal_debug(move,board)); + + return legal; +} + +// filter_legal() + +void filter_legal(list_t * list, const board_t * board) { + + int pos; + int i, move, value; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + pos = 0; + + for (i = 0; i < list_size(list); i++) { + + ASSERT(pos>=0&&pos<=i); + + move = list_move(list,i); + value = list_value(list,i); + + if (pseudo_is_legal(move,board)) { + list->move[pos] = move; + list->value[pos] = value; + pos++; + } + } + + ASSERT(pos>=0&&pos<=list_size(list)); + list->size = pos; +} + +// move_is_legal_debug() + +static bool move_is_legal_debug(int move, const board_t * board) { + + list_t list[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + gen_legal_moves(list,board); + + return list_contain(list,move); +} + +// end of move_legal.cpp + diff --git a/move_legal.h b/move_legal.h index 67a2af8..4c8fe71 100644 --- a/move_legal.h +++ b/move_legal.h @@ -1,24 +1,24 @@ - -// move_legal.h - -#ifndef MOVE_LEGAL_H -#define MOVE_LEGAL_H - -// includes - -#include "board.h" -#include "list.h" -#include "util.h" - -// functions - -extern bool move_is_pseudo (int move, const board_t * board); -extern bool pseudo_is_legal (int move, const board_t * board); -extern bool move_is_legal (int move, const board_t * board); - -extern void filter_legal (list_t * list, const board_t * board); - -#endif // !defined MOVE_LEGAL_H - -// end of move_legal.h - + +// move_legal.h + +#ifndef MOVE_LEGAL_H +#define MOVE_LEGAL_H + +// includes + +#include "board.h" +#include "list.h" +#include "util.h" + +// functions + +extern bool move_is_pseudo (int move, const board_t * board); +extern bool pseudo_is_legal (int move, const board_t * board); +extern bool move_is_legal (int move, const board_t * board); + +extern void filter_legal (list_t * list, const board_t * board); + +#endif // !defined MOVE_LEGAL_H + +// end of move_legal.h + diff --git a/option.c b/option.c index 46f4338..8dfae10 100644 --- a/option.c +++ b/option.c @@ -1,398 +1,397 @@ - -// option.c - -// includes - -#include -#include - -#include "option.h" -#include "util.h" - - -// defines - -#define NNB { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL } - -// constants - -static const bool UseDebug = FALSE; -static const int StringSize = 4096; - -// variables - - -option_list_t Option[1]; - -option_t DefaultOptions[] = { - // options - - { "SettingsFile", "file","0","0", "polyglot.ini", NULL,0,NNB, PG|XBOARD|XBSEL}, - - { "SettingsDir", "path","0","0", "" , NULL,0,NNB, PG}, - - { "OnlyWbOptions", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD}, - - { "EngineName", "string","0","0", "" , NULL,0,NNB, PG}, - { "EngineDir", "path","0","0", "." , NULL,0,NNB, PG}, - { "EngineCommand", "string","0","0", "" , NULL,0,NNB, PG}, - - { "Log", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, - { "LogFile", "file","0","0", "polyglot.log", NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, - - { "UCI", "check","0","0", "false" , NULL,0,NNB, PG}, - - { "UseNice", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|UCI}, - { "NiceValue", "spin", "0","20", "5" , NULL,0,NNB, PG|XBOARD|UCI}, - - { "Resign", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL}, - { "ResignMoves", "spin","0","10000", "3" , NULL,0,NNB, PG|XBOARD|XBSEL}, - { "ResignScore", "spin","0","10000", "600" , NULL,0,NNB, PG|XBOARD|XBSEL}, - - { "MateScore", "spin","0","100000", "10000" , NULL,0,NNB, PG|XBOARD}, - - { "Book", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, - { "BookFile", "file","0","0", "book.bin" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, - - { "BookRandom", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, - { "BookDepth", "spin","0","256", "256" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, - { "BookTreshold", "spin","0","1000", "5" , NULL,0,NNB, PG|XBOARD|UCI}, - { "BookLearn", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, - - { "KibitzMove", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, - { "KibitzPV", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, - - { "KibitzCommand", "string","0","0", "tellall" , NULL,0,NNB, PG|XBOARD}, - { "KibitzDelay", "spin","0","1000", "5" , NULL,0,NNB, PG|XBOARD}, - { "KibitzInterval", "spin","0","1000", "0" , NULL,0,NNB, PG|XBOARD}, - - { "ShowPonder", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD}, - { "ScoreWhite", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, - - // work-arounds - - { "UCIVersion", "spin","1","2", "2" , NULL,0,NNB, PG|XBOARD}, - { "CanPonder", "check","1","2", "false" , NULL,0,NNB, PG|XBOARD}, - { "SyncStop", "check","1","2", "false" , NULL,0,NNB, PG|XBOARD|XBSEL}, - { "Affinity", "spin","-1","32", "-1" , NULL,0,NNB, PG}, - { "RepeatPV", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD}, - { "PromoteWorkAround","check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, - - // internal - - { "Chess960", "check","0","0", "false" , NULL,0,NNB, PG}, - - // These options flag various hacks in the source to work around - // WB quirks. They will eventually all be set to false. Probably - // in 4.5.0 - - { "WbWorkArounds", "check","0","0", "true" , NULL,0,NNB, PG}, - { "WbWorkArounds2", "check","0","0", "false" , NULL,0,NNB, PG}, - { "WbWorkArounds3", "check","0","0", "true" , NULL,0,NNB, PG}, - - // Buttons - - { "Save", "save","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL}, - - // Sentinel - - { NULL, NULL,"0","0", NULL , NULL,0,NNB, 0}, - -}; - - -// functions - -// option_is_ok() - -bool option_is_ok(const option_list_t *option) { - if(option->option_nb<0 || option->option_nb>=OptionNb){ - return FALSE; - } - return TRUE; -} - -// option_init_pg() - -void option_init_pg() { - - int i; - option_t *p=DefaultOptions; - char *home_dir; - char SettingsDir[StringSize]; - - option_init(Option); - while(p){ - if(p->name){ - option_insert(Option,p); - p++; - }else{ - break; - } - } - for(i=0;ioption_nb;i++){ - Option->options[i].value=my_strdup(Option->options[i].default_); - } -#ifndef _WIN32 - home_dir=getenv("HOME"); - if(!home_dir){ - home_dir="."; - } - snprintf(SettingsDir,sizeof(SettingsDir),"%s/.polyglot",home_dir); - SettingsDir[sizeof(SettingsDir)-1]='\0'; -#else - sprintf(SettingsDir,".\\_PG"); -#endif - option_set(Option,"SettingsDir",SettingsDir); - option_set_default(Option,"SettingsDir",SettingsDir); -} - -// option_init() - -void option_init(option_list_t *option){ - ASSERT(option!=NULL); - option->option_nb=0; - option->iter=0; - memset(option->options,0,sizeof(option->options)); -} - -// option_insert() - -void option_insert(option_list_t *option, option_t *new_option){ - int i; - option_t *opt; - ASSERT(option!=NULL); - ASSERT(new_option!=NULL); - ASSERT(new_option->name!=NULL); - opt=option_find(option,new_option->name); - if(!opt){ - opt=&option->options[option->option_nb]; - option->option_nb++; - } - if(option->option_nb>=OptionNb){ - my_fatal("option_insert(): option list overflow\n"); - } - if(new_option->name) my_string_set(&opt->name, new_option->name); - if(new_option->value) my_string_set(&opt->value, new_option->value); - if(new_option->min) my_string_set(&opt->min, new_option->min); - if(new_option->max) my_string_set(&opt->max, new_option->max); - if(new_option->default_) my_string_set(&opt->default_, new_option->default_); - if(new_option->type) my_string_set(&opt->type, new_option->type); - opt->var_nb=new_option->var_nb; - for(i=0;ivar_nb;i++){ - my_string_set(&opt->var[i], new_option->var[i]); - } - opt->mode=new_option->mode; -} - -// option_set() - -bool option_set(option_list_t *option, - const char name[], - const char value[]) { - - option_t * opt; - ASSERT(option!=NULL); - ASSERT(name!=NULL); - ASSERT(value!=NULL); - - opt = option_find(option,name); - if (opt == NULL) return FALSE; - - if(my_string_case_equal(opt->type,"check")){ - value=(my_string_equal(value,"1")|| - my_string_case_equal(value,"true"))?"true":"false"; - } - - my_string_set(&opt->value,value); - - if (UseDebug) my_log("POLYGLOT OPTION SET \"%s\" -> \"%s\"\n",opt->name,opt->value); - - return TRUE; -} - -// option_set_default() - -bool option_set_default(option_list_t *option, - const char name[], - const char value[]) { - - option_t * opt; - ASSERT(name!=NULL); - ASSERT(value!=NULL); - - opt = option_find(option,name); - if (opt == NULL) return FALSE; - - if(my_string_case_equal(opt->type,"check")){ - value=(my_string_equal(value,"1")|| - my_string_case_equal(value,"true"))?"true":"false"; - } - - my_string_set(&opt->default_,value); - - if (UseDebug) my_log("POLYGLOT OPTION DEFAULT SET \"%s\" -> \"%s\"\n",opt->name,opt->default_); - - return TRUE; -} - -// option_get() - -const char * option_get(option_list_t *option, const char name[]) { - - option_t * opt; - - ASSERT(name!=NULL); - - opt = option_find(option,name); - if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name); - if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value); - - return opt->value; -} - -// option_get_default() - -const char * option_get_default(option_list_t *option, const char name[]) { - - option_t * opt; - - ASSERT(name!=NULL); - - opt = option_find(option,name); - if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name); - - if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value); - - return opt->default_; -} - -// option_get_bool() - -bool option_get_bool(option_list_t *option, const char name[]) { - - const char * value; - - value = option_get(option,name); - - if (FALSE) { - } else if (my_string_case_equal(value,"true") || my_string_case_equal(value,"yes") || my_string_equal(value,"1")) { - return TRUE; - } else if (my_string_case_equal(value,"false") || my_string_case_equal(value,"no") || my_string_equal(value,"0")) { - return FALSE; - } - - ASSERT(FALSE); - - return FALSE; -} - - -// option_get_double() - -double option_get_double(option_list_t *option, const char name[]) { - - const char * value; - - value = option_get(option,name); - - return atof(value); -} - -// option_get_int() - -int option_get_int(option_list_t *option, const char name[]) { - - const char * value; - - value = option_get(option,name); - - return atoi(value); -} - -// option_get_string() - -const char * option_get_string(option_list_t *option, const char name[]) { - - const char * value; - - value = option_get(option,name); - - return value; -} - -// option_find() - -option_t * option_find(option_list_t *option, const char name[]) { - - option_t * opt; - int i; - - ASSERT(name!=NULL); - for (i=0; ioption_nb; i++){ - opt=option->options+i; - if (my_string_case_equal(opt->name,name)){ - return opt; - } - } - - return NULL; -} - -// option_start_iter() - -void option_start_iter(option_list_t *option){ - option->iter=0; -} - -// option_next() - -option_t * option_next(option_list_t *option){ - ASSERT(option->iter<=option->option_nb); - if(option->iter==option->option_nb){ - return NULL; - } - return &option->options[option->iter++]; - -} - -void option_free(option_t *option){ - int i; - my_string_clear(&option->name); - my_string_clear(&option->type); - my_string_clear(&option->min); - my_string_clear(&option->max); - my_string_clear(&option->default_); - my_string_clear(&option->value); - for(i=0;ivar_nb;i++){ - my_string_clear(&option->var[i]); - } - option->var_nb=0; - option->mode=0; -} - -// option_clear() - -void option_clear(option_list_t *option){ - int i; - for (i = 0; i < option->option_nb; i++) { - option_free(option->options+i); - } - option->option_nb=0; -} - -// option_from_ini() - -void option_from_ini(option_list_t *option, - ini_t *ini, - const char *section){ - ini_entry_t *entry; - ini_start_iter(ini); - while((entry=ini_next(ini))){ - option_set(option,entry->name,entry->value); - option_set_default(option,entry->name,entry->value); - } -} - -// end of option.cpp - + +// option.c + +// includes + +#include +#include + +#include "option.h" +#include "util.h" + + +// defines + +#define NNB { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL } + +// constants + +static const bool UseDebug = FALSE; + +// variables + + +option_list_t Option[1]; + +option_t DefaultOptions[] = { + // options + + { "SettingsFile", "file","0","0", "polyglot.ini", NULL,0,NNB, PG|XBOARD|XBSEL}, + + { "SettingsDir", "path","0","0", "" , NULL,0,NNB, PG}, + + { "OnlyWbOptions", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD}, + + { "EngineName", "string","0","0", "" , NULL,0,NNB, PG}, + { "EngineDir", "path","0","0", "." , NULL,0,NNB, PG}, + { "EngineCommand", "string","0","0", "" , NULL,0,NNB, PG}, + + { "Log", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, + { "LogFile", "file","0","0", "polyglot.log", NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, + + { "UCI", "check","0","0", "false" , NULL,0,NNB, PG}, + + { "UseNice", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|UCI}, + { "NiceValue", "spin", "0","20", "5" , NULL,0,NNB, PG|XBOARD|UCI}, + + { "Resign", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL}, + { "ResignMoves", "spin","0","10000", "3" , NULL,0,NNB, PG|XBOARD|XBSEL}, + { "ResignScore", "spin","0","10000", "600" , NULL,0,NNB, PG|XBOARD|XBSEL}, + + { "MateScore", "spin","0","100000", "10000" , NULL,0,NNB, PG|XBOARD}, + + { "Book", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, + { "BookFile", "file","0","0", "book.bin" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, + + { "BookRandom", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, + { "BookDepth", "spin","0","256", "256" , NULL,0,NNB, PG|XBOARD|XBSEL|UCI}, + { "BookTreshold", "spin","0","1000", "5" , NULL,0,NNB, PG|XBOARD|UCI}, + { "BookLearn", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + { "KibitzMove", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + { "KibitzPV", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + { "KibitzCommand", "string","0","0", "tellall" , NULL,0,NNB, PG|XBOARD}, + { "KibitzDelay", "spin","0","1000", "5" , NULL,0,NNB, PG|XBOARD}, + { "KibitzInterval", "spin","0","1000", "0" , NULL,0,NNB, PG|XBOARD}, + + { "ShowPonder", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD}, + { "ScoreWhite", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + // work-arounds + + { "UCIVersion", "spin","1","2", "2" , NULL,0,NNB, PG|XBOARD}, + { "CanPonder", "check","1","2", "false" , NULL,0,NNB, PG|XBOARD}, + { "SyncStop", "check","1","2", "false" , NULL,0,NNB, PG|XBOARD|XBSEL}, + { "Affinity", "spin","-1","32", "-1" , NULL,0,NNB, PG}, + { "RepeatPV", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD}, + { "PromoteWorkAround","check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + // internal + + { "Chess960", "check","0","0", "false" , NULL,0,NNB, PG}, + + // These options flag various hacks in the source to work around + // WB quirks. They will eventually all be set to false. Probably + // in 4.5.0 + + { "WbWorkArounds", "check","0","0", "true" , NULL,0,NNB, PG}, + { "WbWorkArounds2", "check","0","0", "false" , NULL,0,NNB, PG}, + { "WbWorkArounds3", "check","0","0", "true" , NULL,0,NNB, PG}, + + // Buttons + + { "Save", "save","0","0", "false" , NULL,0,NNB, PG|XBOARD|XBSEL}, + + // Sentinel + + { NULL, NULL,"0","0", NULL , NULL,0,NNB, 0}, + +}; + + +// functions + +// option_is_ok() + +bool option_is_ok(const option_list_t *option) { + if(option->option_nb<0 || option->option_nb>=OptionNb){ + return FALSE; + } + return TRUE; +} + +// option_init_pg() + +void option_init_pg() { + + int i; + option_t *p=DefaultOptions; + char *home_dir; + char SettingsDir[StringSize]; + + option_init(Option); + while(p){ + if(p->name){ + option_insert(Option,p); + p++; + }else{ + break; + } + } + for(i=0;ioption_nb;i++){ + Option->options[i].value=my_strdup(Option->options[i].default_); + } +#ifndef _WIN32 + home_dir=getenv("HOME"); + if(!home_dir){ + home_dir="."; + } + snprintf(SettingsDir,sizeof(SettingsDir),"%s/.polyglot",home_dir); + SettingsDir[sizeof(SettingsDir)-1]='\0'; +#else + sprintf(SettingsDir,".\\_PG"); +#endif + option_set(Option,"SettingsDir",SettingsDir); + option_set_default(Option,"SettingsDir",SettingsDir); +} + +// option_init() + +void option_init(option_list_t *option){ + ASSERT(option!=NULL); + option->option_nb=0; + option->iter=0; + memset(option->options,0,sizeof(option->options)); +} + +// option_insert() + +void option_insert(option_list_t *option, option_t *new_option){ + int i; + option_t *opt; + ASSERT(option!=NULL); + ASSERT(new_option!=NULL); + ASSERT(new_option->name!=NULL); + opt=option_find(option,new_option->name); + if(!opt){ + opt=&option->options[option->option_nb]; + option->option_nb++; + } + if(option->option_nb>=OptionNb){ + my_fatal("option_insert(): option list overflow\n"); + } + if(new_option->name) my_string_set(&opt->name, new_option->name); + if(new_option->value) my_string_set(&opt->value, new_option->value); + if(new_option->min) my_string_set(&opt->min, new_option->min); + if(new_option->max) my_string_set(&opt->max, new_option->max); + if(new_option->default_) my_string_set(&opt->default_, new_option->default_); + if(new_option->type) my_string_set(&opt->type, new_option->type); + opt->var_nb=new_option->var_nb; + for(i=0;ivar_nb;i++){ + my_string_set(&opt->var[i], new_option->var[i]); + } + opt->mode=new_option->mode; +} + +// option_set() + +bool option_set(option_list_t *option, + const char name[], + const char value[]) { + + option_t * opt; + ASSERT(option!=NULL); + ASSERT(name!=NULL); + ASSERT(value!=NULL); + + opt = option_find(option,name); + if (opt == NULL) return FALSE; + + if(my_string_case_equal(opt->type,"check")){ + value=(my_string_equal(value,"1")|| + my_string_case_equal(value,"true"))?"true":"false"; + } + + my_string_set(&opt->value,value); + + if (UseDebug) my_log("POLYGLOT OPTION SET \"%s\" -> \"%s\"\n",opt->name,opt->value); + + return TRUE; +} + +// option_set_default() + +bool option_set_default(option_list_t *option, + const char name[], + const char value[]) { + + option_t * opt; + ASSERT(name!=NULL); + ASSERT(value!=NULL); + + opt = option_find(option,name); + if (opt == NULL) return FALSE; + + if(my_string_case_equal(opt->type,"check")){ + value=(my_string_equal(value,"1")|| + my_string_case_equal(value,"true"))?"true":"false"; + } + + my_string_set(&opt->default_,value); + + if (UseDebug) my_log("POLYGLOT OPTION DEFAULT SET \"%s\" -> \"%s\"\n",opt->name,opt->default_); + + return TRUE; +} + +// option_get() + +const char * option_get(option_list_t *option, const char name[]) { + + option_t * opt; + + ASSERT(name!=NULL); + + opt = option_find(option,name); + if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name); + if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value); + + return opt->value; +} + +// option_get_default() + +const char * option_get_default(option_list_t *option, const char name[]) { + + option_t * opt; + + ASSERT(name!=NULL); + + opt = option_find(option,name); + if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name); + + if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value); + + return opt->default_; +} + +// option_get_bool() + +bool option_get_bool(option_list_t *option, const char name[]) { + + const char * value; + + value = option_get(option,name); + + if (FALSE) { + } else if (my_string_case_equal(value,"true") || my_string_case_equal(value,"yes") || my_string_equal(value,"1")) { + return TRUE; + } else if (my_string_case_equal(value,"false") || my_string_case_equal(value,"no") || my_string_equal(value,"0")) { + return FALSE; + } + + ASSERT(FALSE); + + return FALSE; +} + + +// option_get_double() + +double option_get_double(option_list_t *option, const char name[]) { + + const char * value; + + value = option_get(option,name); + + return atof(value); +} + +// option_get_int() + +int option_get_int(option_list_t *option, const char name[]) { + + const char * value; + + value = option_get(option,name); + + return atoi(value); +} + +// option_get_string() + +const char * option_get_string(option_list_t *option, const char name[]) { + + const char * value; + + value = option_get(option,name); + + return value; +} + +// option_find() + +option_t * option_find(option_list_t *option, const char name[]) { + + option_t * opt; + int i; + + ASSERT(name!=NULL); + for (i=0; ioption_nb; i++){ + opt=option->options+i; + if (my_string_case_equal(opt->name,name)){ + return opt; + } + } + + return NULL; +} + +// option_start_iter() + +void option_start_iter(option_list_t *option){ + option->iter=0; +} + +// option_next() + +option_t * option_next(option_list_t *option){ + ASSERT(option->iter<=option->option_nb); + if(option->iter==option->option_nb){ + return NULL; + } + return &option->options[option->iter++]; + +} + +void option_free(option_t *option){ + int i; + my_string_clear(&option->name); + my_string_clear(&option->type); + my_string_clear(&option->min); + my_string_clear(&option->max); + my_string_clear(&option->default_); + my_string_clear(&option->value); + for(i=0;ivar_nb;i++){ + my_string_clear(&option->var[i]); + } + option->var_nb=0; + option->mode=0; +} + +// option_clear() + +void option_clear(option_list_t *option){ + int i; + for (i = 0; i < option->option_nb; i++) { + option_free(option->options+i); + } + option->option_nb=0; +} + +// option_from_ini() + +void option_from_ini(option_list_t *option, + ini_t *ini, + const char *section){ + ini_entry_t *entry; + ini_start_iter(ini); + while((entry=ini_next(ini))){ + option_set(option,entry->name,entry->value); + option_set_default(option,entry->name,entry->value); + } +} + +// end of option.cpp + diff --git a/option.h b/option.h index 7a842e6..520df45 100644 --- a/option.h +++ b/option.h @@ -1,98 +1,98 @@ - -// option.h - -#ifndef OPTION_H -#define OPTION_H - -// includes - -#include "util.h" -#include "ini.h" - -// defines - -#define VarNb 16 -#define XBOARD (1<<0) -#define UCI (1<<1) -#define PG (1<<2) -#define XBSEL (1<<3) -#define OptionNb 256 - -#define IS_BUTTON(str) (my_string_case_equal(str,"button") || \ - my_string_case_equal(str,"save") || \ - my_string_case_equal(str,"reset")) \ - -#define IS_SPIN(str) (my_string_case_equal(str,"spin") || \ - my_string_case_equal(str,"slider")) \ - -#define IS_STRING(str) (my_string_case_equal(str,"string") || \ - my_string_case_equal(str,"path") || \ - my_string_case_equal(str,"file")) \ - -// types - -typedef struct { // TODO: put back in more logical order - const char * name; - const char * type; - const char * min; - const char * max; - const char * default_; - const char * value; - int var_nb; - const char * var[VarNb]; - int mode; -} option_t; - -// all non NULL data in an option_list_t should be malloc'ed -// use "my_string_set" to fill it. - -typedef struct { - option_t options[OptionNb]; - int option_nb; - int iter; -} option_list_t; - -// variables - -extern option_list_t Option[1]; - -// functions - - -extern void option_init (option_list_t *option); - -extern void option_init_pg (); - -extern bool option_set (option_list_t *option, - const char var[], - const char val[]); -extern bool option_set_default (option_list_t *option, - const char var[], - const char val[]); - -extern const char * option_get (option_list_t *option, const char var[]); -extern const char * option_get_default (option_list_t *option, const char var[]); - -extern bool option_get_bool (option_list_t *option, const char var[]); -extern double option_get_double (option_list_t *option, const char var[]); -extern int option_get_int (option_list_t *option, const char var[]); -extern const char * option_get_string (option_list_t *option, const char var[]); - -extern void option_from_ini (option_list_t *option, - ini_t *ini, - const char *section); - -extern bool option_is_ok (const option_list_t *option); -extern option_t * option_find (option_list_t *option, const char var[]); -extern void option_clear (option_list_t *option); -extern void option_insert (option_list_t *option, option_t *new_option); - -extern void option_start_iter (option_list_t *option); -extern option_t * option_next (option_list_t *option); - -extern void option_free (option_t *option); - -#endif // !defined OPTION_H - -// end of option.h - + +// option.h + +#ifndef OPTION_H +#define OPTION_H + +// includes + +#include "util.h" +#include "ini.h" + +// defines + +#define VarNb 16 +#define XBOARD (1<<0) +#define UCI (1<<1) +#define PG (1<<2) +#define XBSEL (1<<3) +#define OptionNb 256 + +#define IS_BUTTON(str) (my_string_case_equal(str,"button") || \ + my_string_case_equal(str,"save") || \ + my_string_case_equal(str,"reset")) \ + +#define IS_SPIN(str) (my_string_case_equal(str,"spin") || \ + my_string_case_equal(str,"slider")) \ + +#define IS_STRING(str) (my_string_case_equal(str,"string") || \ + my_string_case_equal(str,"path") || \ + my_string_case_equal(str,"file")) \ + +// types + +typedef struct { // TODO: put back in more logical order + const char * name; + const char * type; + const char * min; + const char * max; + const char * default_; + const char * value; + int var_nb; + const char * var[VarNb]; + int mode; +} option_t; + +// all non NULL data in an option_list_t should be malloc'ed +// use "my_string_set" to fill it. + +typedef struct { + option_t options[OptionNb]; + int option_nb; + int iter; +} option_list_t; + +// variables + +extern option_list_t Option[1]; + +// functions + + +extern void option_init (option_list_t *option); + +extern void option_init_pg (); + +extern bool option_set (option_list_t *option, + const char var[], + const char val[]); +extern bool option_set_default (option_list_t *option, + const char var[], + const char val[]); + +extern const char * option_get (option_list_t *option, const char var[]); +extern const char * option_get_default (option_list_t *option, const char var[]); + +extern bool option_get_bool (option_list_t *option, const char var[]); +extern double option_get_double (option_list_t *option, const char var[]); +extern int option_get_int (option_list_t *option, const char var[]); +extern const char * option_get_string (option_list_t *option, const char var[]); + +extern void option_from_ini (option_list_t *option, + ini_t *ini, + const char *section); + +extern bool option_is_ok (const option_list_t *option); +extern option_t * option_find (option_list_t *option, const char var[]); +extern void option_clear (option_list_t *option); +extern void option_insert (option_list_t *option, option_t *new_option); + +extern void option_start_iter (option_list_t *option); +extern option_t * option_next (option_list_t *option); + +extern void option_free (option_t *option); + +#endif // !defined OPTION_H + +// end of option.h + diff --git a/parse.c b/parse.c index b13b563..a00bf07 100644 --- a/parse.c +++ b/parse.c @@ -1,264 +1,260 @@ - -// parse.c - -// includes - -#include - -#include "parse.h" -#include "util.h" - -// constants - -#define StringSize ((int)256) - -// variables - -char * Star[STAR_NUMBER]; - -// prototypes - -static bool match_rec (char string[], const char pattern[], char * star[]); - -// functions - -// match() - -bool match(char string[], const char pattern[]) { - - ASSERT(string!=NULL); - ASSERT(pattern!=NULL); - - ASSERT(strstr(pattern,"**")==NULL); - - return match_rec(string,pattern,Star); -} - -// match_rec() - -static bool match_rec(char string[], const char pattern[], char * star[]) { - - int c; - - ASSERT(string!=NULL); - ASSERT(pattern!=NULL); - ASSERT(star!=NULL); - - // iterative matches - - while ((c=*pattern++) != '*') { - if (FALSE) { - } else if (c == '\0') { // end of pattern - while (*string == ' ') string++; // skip trailing spaces - return *string == '\0'; - } else if (c == ' ') { // spaces - if (*string++ != ' ') return FALSE; // mismatch - while (*string == ' ') string++; // skip trailing spaces - } else { // normal character - if (*string++ != c) return FALSE; // mismatch - } - } - - // recursive wildcard match - - ASSERT(c=='*'); - - while (*string == ' ') string++; // skip leading spaces - *star++ = string; // remember beginning of star - - while ((c=*string++) != '\0') { // reject empty-string match - if (c != ' ' && match_rec(string,pattern,star)) { // shortest match - ASSERT(string>star[-1]); - *string = '\0'; // truncate star - return TRUE; - } - } - - return FALSE; -} - -// parse_is_ok() - -bool parse_is_ok(const parse_t * parse) { - - if (parse == NULL) return FALSE; - if (parse->string == NULL) return FALSE; - if (parse->pos < 0 || parse->pos > (int) strlen(parse->string)) return FALSE; - if (parse->keyword_nb < 0 || parse->keyword_nb >= KEYWORD_NUMBER) return FALSE; - - return TRUE; -} - -// parse_open() - -void parse_open(parse_t * parse, const char string[]) { - - ASSERT(parse!=NULL); - ASSERT(string!=NULL); - - parse->string = string; - parse->pos = 0; - parse->keyword_nb = 0; -} - -// parse_close() - -void parse_close(parse_t * parse) { - - int i; - - ASSERT(parse_is_ok(parse)); - - parse->string = NULL; - parse->pos = 0; - - for (i = 0; i < parse->keyword_nb; i++) { - my_string_clear(&parse->keyword[i]); - } - - parse->keyword_nb = 0; -} - -// parse_add_keyword() - -void parse_add_keyword(parse_t * parse, const char keyword[]) { - - const char * * string; - - ASSERT(parse_is_ok(parse)); - ASSERT(keyword!=NULL); - - if (parse->keyword_nb < KEYWORD_NUMBER) { - - string = &parse->keyword[parse->keyword_nb]; - parse->keyword_nb++; - - *string = NULL; - my_string_set(string,keyword); - } -} - -// parse_get_word() - -bool parse_get_word(parse_t * parse, char string[], int size) { - - int pos; - int c; - - ASSERT(parse!=NULL); - ASSERT(string!=NULL); - ASSERT(size>=256); - - // skip blanks - - for (; parse->string[parse->pos] == ' '; parse->pos++) - ; - - ASSERT(parse->string[parse->pos]!=' '); - - // copy word - - pos = 0; - - while (TRUE) { - - c = parse->string[parse->pos]; - if (c == ' ' || pos >= size-1) c = '\0'; - - string[pos] = c; - if (c == '\0') break; - - parse->pos++; - pos++; - } - - ASSERT(strchr(string,' ')==NULL); - - return pos > 0; // non-empty word? -} - -// parse_get_string() - -bool parse_get_string(parse_t * parse, char string[], int size) { - - int pos; - parse_t parse_2[1]; - char word[StringSize]; - int i; - int c; - - ASSERT(parse!=NULL); - ASSERT(string!=NULL); - ASSERT(size>=256); - - // skip blanks - - for (; parse->string[parse->pos] == ' '; parse->pos++) - ; - - ASSERT(parse->string[parse->pos]!=' '); - - // copy string - - pos = 0; - - while (TRUE) { - - parse_open(parse_2,&parse->string[parse->pos]); - - if (!parse_get_word(parse_2,word,StringSize)) { - string[pos] = '\0'; - parse_close(parse_2); - goto finished; - } - - for (i = 0; i < parse->keyword_nb; i++) { - if (my_string_equal(parse->keyword[i],word)) { - string[pos] = '\0'; - parse_close(parse_2); - goto finished; - } - } - - parse_close(parse_2); - - // copy spaces - - while (TRUE) { - - c = parse->string[parse->pos]; - if (c != ' ') break; - - if (pos >= size-1) c = '\0'; - - string[pos] = c; - if (c == '\0') break; - - parse->pos++; - pos++; - } - - // copy non spaces - - while (TRUE) { - - c = parse->string[parse->pos]; - if (c == ' ' || pos >= size-1) c = '\0'; - - string[pos] = c; - if (c == '\0') break; - - parse->pos++; - pos++; - } - - string[pos] = '\0'; - } - -finished: ; - - return pos > 0; // non-empty string? -} - -// end of parse.cpp - + +// parse.c + +// includes + +#include + +#include "parse.h" +#include "util.h" + +// variables + +char * Star[STAR_NUMBER]; + +// prototypes + +static bool match_rec (char string[], const char pattern[], char * star[]); + +// functions + +// match() + +bool match(char string[], const char pattern[]) { + + ASSERT(string!=NULL); + ASSERT(pattern!=NULL); + + ASSERT(strstr(pattern,"**")==NULL); + + return match_rec(string,pattern,Star); +} + +// match_rec() + +static bool match_rec(char string[], const char pattern[], char * star[]) { + + int c; + + ASSERT(string!=NULL); + ASSERT(pattern!=NULL); + ASSERT(star!=NULL); + + // iterative matches + + while ((c=*pattern++) != '*') { + if (FALSE) { + } else if (c == '\0') { // end of pattern + while (*string == ' ') string++; // skip trailing spaces + return *string == '\0'; + } else if (c == ' ') { // spaces + if (*string++ != ' ') return FALSE; // mismatch + while (*string == ' ') string++; // skip trailing spaces + } else { // normal character + if (*string++ != c) return FALSE; // mismatch + } + } + + // recursive wildcard match + + ASSERT(c=='*'); + + while (*string == ' ') string++; // skip leading spaces + *star++ = string; // remember beginning of star + + while ((c=*string++) != '\0') { // reject empty-string match + if (c != ' ' && match_rec(string,pattern,star)) { // shortest match + ASSERT(string>star[-1]); + *string = '\0'; // truncate star + return TRUE; + } + } + + return FALSE; +} + +// parse_is_ok() + +bool parse_is_ok(const parse_t * parse) { + + if (parse == NULL) return FALSE; + if (parse->string == NULL) return FALSE; + if (parse->pos < 0 || parse->pos > (int) strlen(parse->string)) return FALSE; + if (parse->keyword_nb < 0 || parse->keyword_nb >= KEYWORD_NUMBER) return FALSE; + + return TRUE; +} + +// parse_open() + +void parse_open(parse_t * parse, const char string[]) { + + ASSERT(parse!=NULL); + ASSERT(string!=NULL); + + parse->string = string; + parse->pos = 0; + parse->keyword_nb = 0; +} + +// parse_close() + +void parse_close(parse_t * parse) { + + int i; + + ASSERT(parse_is_ok(parse)); + + parse->string = NULL; + parse->pos = 0; + + for (i = 0; i < parse->keyword_nb; i++) { + my_string_clear(&parse->keyword[i]); + } + + parse->keyword_nb = 0; +} + +// parse_add_keyword() + +void parse_add_keyword(parse_t * parse, const char keyword[]) { + + const char * * string; + + ASSERT(parse_is_ok(parse)); + ASSERT(keyword!=NULL); + + if (parse->keyword_nb < KEYWORD_NUMBER) { + + string = &parse->keyword[parse->keyword_nb]; + parse->keyword_nb++; + + *string = NULL; + my_string_set(string,keyword); + } +} + +// parse_get_word() + +bool parse_get_word(parse_t * parse, char string[], int size) { + + int pos; + int c; + + ASSERT(parse!=NULL); + ASSERT(string!=NULL); + ASSERT(size>=256); + + // skip blanks + + for (; parse->string[parse->pos] == ' '; parse->pos++) + ; + + ASSERT(parse->string[parse->pos]!=' '); + + // copy word + + pos = 0; + + while (TRUE) { + + c = parse->string[parse->pos]; + if (c == ' ' || pos >= size-1) c = '\0'; + + string[pos] = c; + if (c == '\0') break; + + parse->pos++; + pos++; + } + + ASSERT(strchr(string,' ')==NULL); + + return pos > 0; // non-empty word? +} + +// parse_get_string() + +bool parse_get_string(parse_t * parse, char string[], int size) { + + int pos; + parse_t parse_2[1]; + char word[StringSize]; + int i; + int c; + + ASSERT(parse!=NULL); + ASSERT(string!=NULL); + ASSERT(size>=256); + + // skip blanks + + for (; parse->string[parse->pos] == ' '; parse->pos++) + ; + + ASSERT(parse->string[parse->pos]!=' '); + + // copy string + + pos = 0; + + while (TRUE) { + + parse_open(parse_2,&parse->string[parse->pos]); + + if (!parse_get_word(parse_2,word,StringSize)) { + string[pos] = '\0'; + parse_close(parse_2); + goto finished; + } + + for (i = 0; i < parse->keyword_nb; i++) { + if (my_string_equal(parse->keyword[i],word)) { + string[pos] = '\0'; + parse_close(parse_2); + goto finished; + } + } + + parse_close(parse_2); + + // copy spaces + + while (TRUE) { + + c = parse->string[parse->pos]; + if (c != ' ') break; + + if (pos >= size-1) c = '\0'; + + string[pos] = c; + if (c == '\0') break; + + parse->pos++; + pos++; + } + + // copy non spaces + + while (TRUE) { + + c = parse->string[parse->pos]; + if (c == ' ' || pos >= size-1) c = '\0'; + + string[pos] = c; + if (c == '\0') break; + + parse->pos++; + pos++; + } + + string[pos] = '\0'; + } + +finished: ; + + return pos > 0; // non-empty string? +} + +// end of parse.cpp + diff --git a/parse.h b/parse.h index 5c35b32..cca5de6 100644 --- a/parse.h +++ b/parse.h @@ -1,44 +1,44 @@ - -// parse.h - -#ifndef PARSE_H -#define PARSE_H - -// includes - -#include "util.h" - -// defined - -#define STAR_NUMBER 16 -#define KEYWORD_NUMBER 256 - -// types - -typedef struct { - const char * string; - int pos; - int keyword_nb; - const char * keyword[KEYWORD_NUMBER]; -} parse_t; - -// variables - -extern char * Star[STAR_NUMBER]; - -// functions - -extern bool match (char string[], const char pattern[]); - -extern void parse_open (parse_t * parse, const char string[]); -extern void parse_close (parse_t * parse); - -extern void parse_add_keyword (parse_t * parse, const char keyword[]); - -extern bool parse_get_word (parse_t * parse, char string[], int size); -extern bool parse_get_string (parse_t * parse, char string[], int size); - -#endif // !defined PARSE_H - -// end of parse.h - + +// parse.h + +#ifndef PARSE_H +#define PARSE_H + +// includes + +#include "util.h" + +// defined + +#define STAR_NUMBER 16 +#define KEYWORD_NUMBER 256 + +// types + +typedef struct { + const char * string; + int pos; + int keyword_nb; + const char * keyword[KEYWORD_NUMBER]; +} parse_t; + +// variables + +extern char * Star[STAR_NUMBER]; + +// functions + +extern bool match (char string[], const char pattern[]); + +extern void parse_open (parse_t * parse, const char string[]); +extern void parse_close (parse_t * parse); + +extern void parse_add_keyword (parse_t * parse, const char keyword[]); + +extern bool parse_get_word (parse_t * parse, char string[], int size); +extern bool parse_get_string (parse_t * parse, char string[], int size); + +#endif // !defined PARSE_H + +// end of parse.h + diff --git a/pgn.c b/pgn.c index 3de7483..aabd4e1 100644 --- a/pgn.c +++ b/pgn.c @@ -1,641 +1,641 @@ - -// pgn.c - -// includes - -#include -#include -#include -#include - -#include "pgn.h" -#include "util.h" - -// constants - -static const bool DispMove = FALSE; -static const bool DispToken = FALSE; -static const bool DispChar = FALSE; - -static const int TAB_SIZE = 8; - -static const int CHAR_EOF = 256; - -// types - -enum token_t { - TOKEN_ERROR = -1, - TOKEN_EOF = 256, - TOKEN_SYMBOL = 257, - TOKEN_STRING = 258, - TOKEN_INTEGER = 259, - TOKEN_NAG = 260, - TOKEN_RESULT = 261 -}; - -// prototypes - -static void pgn_token_read (pgn_t * pgn); -static void pgn_token_unread (pgn_t * pgn); - -static void pgn_read_token (pgn_t * pgn); - -static bool is_symbol_start (int c); -static bool is_symbol_next (int c); - -static void pgn_skip_blanks (pgn_t * pgn); - -static void pgn_char_read (pgn_t * pgn); -static void pgn_char_unread (pgn_t * pgn); - -// functions - -// pgn_open() - -void pgn_open(pgn_t * pgn, const char file_name[]) { - - ASSERT(pgn!=NULL); - ASSERT(file_name!=NULL); - - pgn->file = fopen(file_name,"r"); - if (pgn->file == NULL) my_fatal("pgn_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); - - pgn->char_hack = CHAR_EOF; // DEBUG - pgn->char_line = 1; - pgn->char_column = 0; - pgn->char_unread = FALSE; - pgn->char_first = TRUE; - - pgn->token_type = TOKEN_ERROR; // DEBUG - strcpy(pgn->token_string,"?"); // DEBUG - pgn->token_length = -1; // DEBUG - pgn->token_line = -1; // DEBUG - pgn->token_column = -1; // DEBUG - pgn->token_unread = FALSE; - pgn->token_first = TRUE; - - strcpy(pgn->result,"?"); // DEBUG - strcpy(pgn->fen,"?"); // DEBUG - - pgn->move_line = -1; // DEBUG - pgn->move_column = -1; // DEBUG -} - -// pgn_close() - -void pgn_close(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - fclose(pgn->file); -} - -// pgn_next_game() - -bool pgn_next_game(pgn_t * pgn) { - - char name[PGN_STRING_SIZE]; - char value[PGN_STRING_SIZE]; - - ASSERT(pgn!=NULL); - - // init - - strcpy(pgn->result,"*"); - strcpy(pgn->fen,""); - - // loop - - while (TRUE) { - - pgn_token_read(pgn); - - if (pgn->token_type != '[') break; - - // tag - - pgn_token_read(pgn); - if (pgn->token_type != TOKEN_SYMBOL) { - my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - strcpy(name,pgn->token_string); - - pgn_token_read(pgn); - if (pgn->token_type != TOKEN_STRING) { - my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - strcpy(value,pgn->token_string); - - pgn_token_read(pgn); - if (pgn->token_type != ']') { - my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - - // special tag? - - if (FALSE) { - } else if (my_string_equal(name,"Result")) { - strcpy(pgn->result,value); - } else if (my_string_equal(name,"FEN")) { - strcpy(pgn->fen,value); - } - } - - if (pgn->token_type == TOKEN_EOF) return FALSE; - - pgn_token_unread(pgn); - - return TRUE; -} - -// pgn_next_move() - -bool pgn_next_move(pgn_t * pgn, char string[], int size) { - - int depth; - - ASSERT(pgn!=NULL); - ASSERT(string!=NULL); - ASSERT(size>=PGN_STRING_SIZE); - - // init - - pgn->move_line = -1; // DEBUG - pgn->move_column = -1; // DEBUG - - // loop - - depth = 0; - - while (TRUE) { - - pgn_token_read(pgn); - - if (FALSE) { - - } else if (pgn->token_type == '(') { - - // open RAV - - depth++; - - } else if (pgn->token_type == ')') { - - // close RAV - - if (depth == 0) { - my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - - depth--; - ASSERT(depth>=0); - - } else if (pgn->token_type == TOKEN_RESULT) { - - // game finished - - if (depth > 0) { - my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - - return FALSE; - - } else { - - // skip optional move number - - if (pgn->token_type == TOKEN_INTEGER) { - do pgn_token_read(pgn); while (pgn->token_type == '.'); - } - - // move must be a symbol - - if (pgn->token_type != TOKEN_SYMBOL) { - my_fatal("pgn_next_move(): malformed move at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - - // store move for later use - - if (depth == 0) { - - if (pgn->token_length >= size) { - my_fatal("pgn_next_move(): move too long at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); - } - - strcpy(string,pgn->token_string); - pgn->move_line = pgn->token_line; - pgn->move_column = pgn->token_column; - } - - // skip optional NAGs - - do pgn_token_read(pgn); while (pgn->token_type == TOKEN_NAG); - pgn_token_unread(pgn); - - // return move - - if (depth == 0) { - if (DispMove) printf("move=\"%s\"\n",string); - return TRUE; - } - } - } - - ASSERT(FALSE); - - return FALSE; -} - -// pgn_token_read() - -static void pgn_token_read(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - // token "stack" - - if (pgn->token_unread) { - pgn->token_unread = FALSE; - return; - } - - // consume the current token - - if (pgn->token_first) { - pgn->token_first = FALSE; - } else { - ASSERT(pgn->token_type!=TOKEN_ERROR); - ASSERT(pgn->token_type!=TOKEN_EOF); - } - - // read a new token - - pgn_read_token(pgn); - if (pgn->token_type == TOKEN_ERROR) my_fatal("pgn_token_read(): lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - - if (DispToken) printf("< L%d C%d \"%s\" (%03X)\n",pgn->token_line,pgn->token_column,pgn->token_string,pgn->token_type); -} - -// pgn_token_unread() - -static void pgn_token_unread(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - ASSERT(!pgn->token_unread); - ASSERT(!pgn->token_first); - - pgn->token_unread = TRUE; -} - -// pgn_read_token() - -static void pgn_read_token(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - // skip white-space characters - - pgn_skip_blanks(pgn); - - // init - - pgn->token_type = TOKEN_ERROR; - strcpy(pgn->token_string,""); - pgn->token_length = 0; - pgn->token_line = pgn->char_line; - pgn->token_column = pgn->char_column; - - // determine token type - - if (FALSE) { - - } else if (pgn->char_hack == CHAR_EOF) { - - pgn->token_type = TOKEN_EOF; - - } else if (strchr(".[]()<>",pgn->char_hack) != NULL) { - - // single-character token - - pgn->token_type = pgn->char_hack; - sprintf(pgn->token_string,"%c",pgn->char_hack); - pgn->token_length = 1; - - } else if (pgn->char_hack == '*') { - - pgn->token_type = TOKEN_RESULT; - sprintf(pgn->token_string,"%c",pgn->char_hack); - pgn->token_length = 1; - - } else if (pgn->char_hack == '!') { - - pgn_char_read(pgn); - - if (FALSE) { - - } else if (pgn->char_hack == '!') { // "!!" - - pgn->token_type = TOKEN_NAG; - strcpy(pgn->token_string,"3"); - pgn->token_length = 1; - - } else if (pgn->char_hack == '?') { // "!?" - - pgn->token_type = TOKEN_NAG; - strcpy(pgn->token_string,"5"); - pgn->token_length = 1; - - } else { // "!" - - pgn_char_unread(pgn); - - pgn->token_type = TOKEN_NAG; - strcpy(pgn->token_string,"1"); - pgn->token_length = 1; - } - - } else if (pgn->char_hack == '?') { - - pgn_char_read(pgn); - - if (FALSE) { - - } else if (pgn->char_hack == '?') { // "??" - - pgn->token_type = TOKEN_NAG; - strcpy(pgn->token_string,"4"); - pgn->token_length = 1; - - } else if (pgn->char_hack == '!') { // "?!" - - pgn->token_type = TOKEN_NAG; - strcpy(pgn->token_string,"6"); - pgn->token_length = 1; - - } else { // "?" - - pgn_char_unread(pgn); - - pgn->token_type = TOKEN_NAG; - strcpy(pgn->token_string,"2"); - pgn->token_length = 1; - } - - } else if (is_symbol_start(pgn->char_hack)) { - - // symbol, integer, or result - - pgn->token_type = TOKEN_INTEGER; - pgn->token_length = 0; - - do { - - if (pgn->token_length >= PGN_STRING_SIZE-1) { - my_fatal("pgn_read_token(): symbol too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - if (!isdigit(pgn->char_hack)) pgn->token_type = TOKEN_SYMBOL; - - pgn->token_string[pgn->token_length++] = pgn->char_hack; - - pgn_char_read(pgn); - - } while (is_symbol_next(pgn->char_hack)); - - pgn_char_unread(pgn); - - ASSERT(pgn->token_length>0&&pgn->token_lengthtoken_string[pgn->token_length] = '\0'; - - if (my_string_equal(pgn->token_string,"1-0") - || my_string_equal(pgn->token_string,"0-1") - || my_string_equal(pgn->token_string,"1/2-1/2")) { - pgn->token_type = TOKEN_RESULT; - } - - } else if (pgn->char_hack == '"') { - - // string - - pgn->token_type = TOKEN_STRING; - pgn->token_length = 0; - - while (TRUE) { - - pgn_char_read(pgn); - - if (pgn->char_hack == CHAR_EOF) { - my_fatal("pgn_read_token(): EOF in string at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - if (pgn->char_hack == '"') break; - - if (pgn->char_hack == '\\') { - - pgn_char_read(pgn); - - if (pgn->char_hack == CHAR_EOF) { - my_fatal("pgn_read_token(): EOF in string at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - if (pgn->char_hack != '"' && pgn->char_hack != '\\') { - - // bad escape, ignore - - if (pgn->token_length >= PGN_STRING_SIZE-1) { - my_fatal("pgn_read_token(): string too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - pgn->token_string[pgn->token_length++] = '\\'; - } - } - - if (pgn->token_length >= PGN_STRING_SIZE-1) { - my_fatal("pgn_read_token(): string too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - pgn->token_string[pgn->token_length++] = pgn->char_hack; - } - - ASSERT(pgn->token_length>=0&&pgn->token_lengthtoken_string[pgn->token_length] = '\0'; - - } else if (pgn->char_hack == '$') { - - // NAG - - pgn->token_type = TOKEN_NAG; - pgn->token_length = 0; - - while (TRUE) { - - pgn_char_read(pgn); - - if (!isdigit(pgn->char_hack)) break; - - if (pgn->token_length >= 3) { - my_fatal("pgn_read_token(): NAG too long at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - pgn->token_string[pgn->token_length++] = pgn->char_hack; - } - - pgn_char_unread(pgn); - - if (pgn->token_length == 0) { - my_fatal("pgn_read_token(): malformed NAG at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - ASSERT(pgn->token_length>0&&pgn->token_length<=3); - pgn->token_string[pgn->token_length] = '\0'; - - } else { - - // unknown token - - my_fatal("lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } -} - -// pgn_skip_blanks() - -static void pgn_skip_blanks(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - while (TRUE) { - - pgn_char_read(pgn); - - if (FALSE) { - }else if(pgn->char_hack==CHAR_EOF){ break; - } else if (isspace(pgn->char_hack)) { - - // skip white space - - } else if (pgn->char_hack == ';') { - - // skip comment to EOL - - do { - - pgn_char_read(pgn); - - if (pgn->char_hack == CHAR_EOF) { - my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - } while (pgn->char_hack != '\n'); - - } else if (pgn->char_hack == '%' && pgn->char_column == 0) { - - // skip comment to EOL - - do { - - pgn_char_read(pgn); - - if (pgn->char_hack == CHAR_EOF) { - my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - } while (pgn->char_hack != '\n'); - - } else if (pgn->char_hack == '{') { - - // skip comment to next '}' - - do { - - pgn_char_read(pgn); - - if (pgn->char_hack == CHAR_EOF) { - my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); - } - - } while (pgn->char_hack != '}'); - - } else { // not a white space - - break; - } - } -} - -// is_symbol_start() - -static bool is_symbol_start(int c) { - - return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",c) != NULL; -} - -// is_symbol_next() - -static bool is_symbol_next(int c) { - - return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+#=:-/",c) != NULL; -} - -// pgn_char_read() - -static void pgn_char_read(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - // char "stack" - - if (pgn->char_unread) { - pgn->char_unread = FALSE; - return; - } - - // consume the current character - - if (pgn->char_first) { - - pgn->char_first = FALSE; - - } else { - - // update counters - - ASSERT(pgn->char_hack!=CHAR_EOF); - - if (FALSE) { - } else if (pgn->char_hack == '\n') { - pgn->char_line++; - pgn->char_column = 0; - } else if (pgn->char_hack == '\t') { - pgn->char_column += TAB_SIZE - (pgn->char_column % TAB_SIZE); - } else { - pgn->char_column++; - } - } - - // read a new character - - pgn->char_hack = fgetc(pgn->file); - - if (pgn->char_hack == EOF) { - if (ferror(pgn->file)) my_fatal("pgn_char_read(): fgetc(): %s\n",strerror(errno)); - pgn->char_hack = CHAR_EOF; - } - - if (DispChar) printf("< L%d C%d '%c' (%02X)\n",pgn->char_line,pgn->char_column,pgn->char_hack,pgn->char_hack); -} - -// pgn_char_unread() - -static void pgn_char_unread(pgn_t * pgn) { - - ASSERT(pgn!=NULL); - - ASSERT(!pgn->char_unread); - ASSERT(!pgn->char_first); - - pgn->char_unread = TRUE; -} - -// end of pgn.cpp - + +// pgn.c + +// includes + +#include +#include +#include +#include + +#include "pgn.h" +#include "util.h" + +// constants + +static const bool DispMove = FALSE; +static const bool DispToken = FALSE; +static const bool DispChar = FALSE; + +static const int TAB_SIZE = 8; + +static const int CHAR_EOF = 256; + +// types + +enum token_t { + TOKEN_ERROR = -1, + TOKEN_EOF = 256, + TOKEN_SYMBOL = 257, + TOKEN_STRING = 258, + TOKEN_INTEGER = 259, + TOKEN_NAG = 260, + TOKEN_RESULT = 261 +}; + +// prototypes + +static void pgn_token_read (pgn_t * pgn); +static void pgn_token_unread (pgn_t * pgn); + +static void pgn_read_token (pgn_t * pgn); + +static bool is_symbol_start (int c); +static bool is_symbol_next (int c); + +static void pgn_skip_blanks (pgn_t * pgn); + +static void pgn_char_read (pgn_t * pgn); +static void pgn_char_unread (pgn_t * pgn); + +// functions + +// pgn_open() + +void pgn_open(pgn_t * pgn, const char file_name[]) { + + ASSERT(pgn!=NULL); + ASSERT(file_name!=NULL); + + pgn->file = fopen(file_name,"r"); + if (pgn->file == NULL) my_fatal("pgn_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + + pgn->char_hack = CHAR_EOF; // DEBUG + pgn->char_line = 1; + pgn->char_column = 0; + pgn->char_unread = FALSE; + pgn->char_first = TRUE; + + pgn->token_type = TOKEN_ERROR; // DEBUG + strcpy(pgn->token_string,"?"); // DEBUG + pgn->token_length = -1; // DEBUG + pgn->token_line = -1; // DEBUG + pgn->token_column = -1; // DEBUG + pgn->token_unread = FALSE; + pgn->token_first = TRUE; + + strcpy(pgn->result,"?"); // DEBUG + strcpy(pgn->fen,"?"); // DEBUG + + pgn->move_line = -1; // DEBUG + pgn->move_column = -1; // DEBUG +} + +// pgn_close() + +void pgn_close(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + fclose(pgn->file); +} + +// pgn_next_game() + +bool pgn_next_game(pgn_t * pgn) { + + char name[PGN_STRING_SIZE]; + char value[PGN_STRING_SIZE]; + + ASSERT(pgn!=NULL); + + // init + + strcpy(pgn->result,"*"); + strcpy(pgn->fen,""); + + // loop + + while (TRUE) { + + pgn_token_read(pgn); + + if (pgn->token_type != '[') break; + + // tag + + pgn_token_read(pgn); + if (pgn->token_type != TOKEN_SYMBOL) { + my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + strcpy(name,pgn->token_string); + + pgn_token_read(pgn); + if (pgn->token_type != TOKEN_STRING) { + my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + strcpy(value,pgn->token_string); + + pgn_token_read(pgn); + if (pgn->token_type != ']') { + my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + // special tag? + + if (FALSE) { + } else if (my_string_equal(name,"Result")) { + strcpy(pgn->result,value); + } else if (my_string_equal(name,"FEN")) { + strcpy(pgn->fen,value); + } + } + + if (pgn->token_type == TOKEN_EOF) return FALSE; + + pgn_token_unread(pgn); + + return TRUE; +} + +// pgn_next_move() + +bool pgn_next_move(pgn_t * pgn, char string[], int size) { + + int depth; + + ASSERT(pgn!=NULL); + ASSERT(string!=NULL); + ASSERT(size>=PGN_STRING_SIZE); + + // init + + pgn->move_line = -1; // DEBUG + pgn->move_column = -1; // DEBUG + + // loop + + depth = 0; + + while (TRUE) { + + pgn_token_read(pgn); + + if (FALSE) { + + } else if (pgn->token_type == '(') { + + // open RAV + + depth++; + + } else if (pgn->token_type == ')') { + + // close RAV + + if (depth == 0) { + my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + depth--; + ASSERT(depth>=0); + + } else if (pgn->token_type == TOKEN_RESULT) { + + // game finished + + if (depth > 0) { + my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + return FALSE; + + } else { + + // skip optional move number + + if (pgn->token_type == TOKEN_INTEGER) { + do pgn_token_read(pgn); while (pgn->token_type == '.'); + } + + // move must be a symbol + + if (pgn->token_type != TOKEN_SYMBOL) { + my_fatal("pgn_next_move(): malformed move at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + // store move for later use + + if (depth == 0) { + + if (pgn->token_length >= size) { + my_fatal("pgn_next_move(): move too long at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + strcpy(string,pgn->token_string); + pgn->move_line = pgn->token_line; + pgn->move_column = pgn->token_column; + } + + // skip optional NAGs + + do pgn_token_read(pgn); while (pgn->token_type == TOKEN_NAG); + pgn_token_unread(pgn); + + // return move + + if (depth == 0) { + if (DispMove) printf("move=\"%s\"\n",string); + return TRUE; + } + } + } + + ASSERT(FALSE); + + return FALSE; +} + +// pgn_token_read() + +static void pgn_token_read(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + // token "stack" + + if (pgn->token_unread) { + pgn->token_unread = FALSE; + return; + } + + // consume the current token + + if (pgn->token_first) { + pgn->token_first = FALSE; + } else { + ASSERT(pgn->token_type!=TOKEN_ERROR); + ASSERT(pgn->token_type!=TOKEN_EOF); + } + + // read a new token + + pgn_read_token(pgn); + if (pgn->token_type == TOKEN_ERROR) my_fatal("pgn_token_read(): lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + + if (DispToken) printf("< L%d C%d \"%s\" (%03X)\n",pgn->token_line,pgn->token_column,pgn->token_string,pgn->token_type); +} + +// pgn_token_unread() + +static void pgn_token_unread(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + ASSERT(!pgn->token_unread); + ASSERT(!pgn->token_first); + + pgn->token_unread = TRUE; +} + +// pgn_read_token() + +static void pgn_read_token(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + // skip white-space characters + + pgn_skip_blanks(pgn); + + // init + + pgn->token_type = TOKEN_ERROR; + strcpy(pgn->token_string,""); + pgn->token_length = 0; + pgn->token_line = pgn->char_line; + pgn->token_column = pgn->char_column; + + // determine token type + + if (FALSE) { + + } else if (pgn->char_hack == CHAR_EOF) { + + pgn->token_type = TOKEN_EOF; + + } else if (strchr(".[]()<>",pgn->char_hack) != NULL) { + + // single-character token + + pgn->token_type = pgn->char_hack; + sprintf(pgn->token_string,"%c",pgn->char_hack); + pgn->token_length = 1; + + } else if (pgn->char_hack == '*') { + + pgn->token_type = TOKEN_RESULT; + sprintf(pgn->token_string,"%c",pgn->char_hack); + pgn->token_length = 1; + + } else if (pgn->char_hack == '!') { + + pgn_char_read(pgn); + + if (FALSE) { + + } else if (pgn->char_hack == '!') { // "!!" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"3"); + pgn->token_length = 1; + + } else if (pgn->char_hack == '?') { // "!?" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"5"); + pgn->token_length = 1; + + } else { // "!" + + pgn_char_unread(pgn); + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"1"); + pgn->token_length = 1; + } + + } else if (pgn->char_hack == '?') { + + pgn_char_read(pgn); + + if (FALSE) { + + } else if (pgn->char_hack == '?') { // "??" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"4"); + pgn->token_length = 1; + + } else if (pgn->char_hack == '!') { // "?!" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"6"); + pgn->token_length = 1; + + } else { // "?" + + pgn_char_unread(pgn); + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"2"); + pgn->token_length = 1; + } + + } else if (is_symbol_start(pgn->char_hack)) { + + // symbol, integer, or result + + pgn->token_type = TOKEN_INTEGER; + pgn->token_length = 0; + + do { + + if (pgn->token_length >= PGN_STRING_SIZE-1) { + my_fatal("pgn_read_token(): symbol too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + if (!isdigit(pgn->char_hack)) pgn->token_type = TOKEN_SYMBOL; + + pgn->token_string[pgn->token_length++] = pgn->char_hack; + + pgn_char_read(pgn); + + } while (is_symbol_next(pgn->char_hack)); + + pgn_char_unread(pgn); + + ASSERT(pgn->token_length>0&&pgn->token_lengthtoken_string[pgn->token_length] = '\0'; + + if (my_string_equal(pgn->token_string,"1-0") + || my_string_equal(pgn->token_string,"0-1") + || my_string_equal(pgn->token_string,"1/2-1/2")) { + pgn->token_type = TOKEN_RESULT; + } + + } else if (pgn->char_hack == '"') { + + // string + + pgn->token_type = TOKEN_STRING; + pgn->token_length = 0; + + while (TRUE) { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + my_fatal("pgn_read_token(): EOF in string at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + if (pgn->char_hack == '"') break; + + if (pgn->char_hack == '\\') { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + my_fatal("pgn_read_token(): EOF in string at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + if (pgn->char_hack != '"' && pgn->char_hack != '\\') { + + // bad escape, ignore + + if (pgn->token_length >= PGN_STRING_SIZE-1) { + my_fatal("pgn_read_token(): string too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + pgn->token_string[pgn->token_length++] = '\\'; + } + } + + if (pgn->token_length >= PGN_STRING_SIZE-1) { + my_fatal("pgn_read_token(): string too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + pgn->token_string[pgn->token_length++] = pgn->char_hack; + } + + ASSERT(pgn->token_length>=0&&pgn->token_lengthtoken_string[pgn->token_length] = '\0'; + + } else if (pgn->char_hack == '$') { + + // NAG + + pgn->token_type = TOKEN_NAG; + pgn->token_length = 0; + + while (TRUE) { + + pgn_char_read(pgn); + + if (!isdigit(pgn->char_hack)) break; + + if (pgn->token_length >= 3) { + my_fatal("pgn_read_token(): NAG too long at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + pgn->token_string[pgn->token_length++] = pgn->char_hack; + } + + pgn_char_unread(pgn); + + if (pgn->token_length == 0) { + my_fatal("pgn_read_token(): malformed NAG at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + ASSERT(pgn->token_length>0&&pgn->token_length<=3); + pgn->token_string[pgn->token_length] = '\0'; + + } else { + + // unknown token + + my_fatal("lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } +} + +// pgn_skip_blanks() + +static void pgn_skip_blanks(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + while (TRUE) { + + pgn_char_read(pgn); + + if (FALSE) { + }else if(pgn->char_hack==CHAR_EOF){ break; + } else if (isspace(pgn->char_hack)) { + + // skip white space + + } else if (pgn->char_hack == ';') { + + // skip comment to EOL + + do { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + } while (pgn->char_hack != '\n'); + + } else if (pgn->char_hack == '%' && pgn->char_column == 0) { + + // skip comment to EOL + + do { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + } while (pgn->char_hack != '\n'); + + } else if (pgn->char_hack == '{') { + + // skip comment to next '}' + + do { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + } while (pgn->char_hack != '}'); + + } else { // not a white space + + break; + } + } +} + +// is_symbol_start() + +static bool is_symbol_start(int c) { + + return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",c) != NULL; +} + +// is_symbol_next() + +static bool is_symbol_next(int c) { + + return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+#=:-/",c) != NULL; +} + +// pgn_char_read() + +static void pgn_char_read(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + // char "stack" + + if (pgn->char_unread) { + pgn->char_unread = FALSE; + return; + } + + // consume the current character + + if (pgn->char_first) { + + pgn->char_first = FALSE; + + } else { + + // update counters + + ASSERT(pgn->char_hack!=CHAR_EOF); + + if (FALSE) { + } else if (pgn->char_hack == '\n') { + pgn->char_line++; + pgn->char_column = 0; + } else if (pgn->char_hack == '\t') { + pgn->char_column += TAB_SIZE - (pgn->char_column % TAB_SIZE); + } else { + pgn->char_column++; + } + } + + // read a new character + + pgn->char_hack = fgetc(pgn->file); + + if (pgn->char_hack == EOF) { + if (ferror(pgn->file)) my_fatal("pgn_char_read(): fgetc(): %s\n",strerror(errno)); + pgn->char_hack = CHAR_EOF; + } + + if (DispChar) printf("< L%d C%d '%c' (%02X)\n",pgn->char_line,pgn->char_column,pgn->char_hack,pgn->char_hack); +} + +// pgn_char_unread() + +static void pgn_char_unread(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + ASSERT(!pgn->char_unread); + ASSERT(!pgn->char_first); + + pgn->char_unread = TRUE; +} + +// end of pgn.cpp + diff --git a/pgn.h b/pgn.h index 0f51015..6bed708 100644 --- a/pgn.h +++ b/pgn.h @@ -1,56 +1,56 @@ - -// pgn.h - -#ifndef PGN_H -#define PGN_H - -// includes - -#include - -#include "util.h" - -// defines - -#define PGN_STRING_SIZE 256 - -// types - -typedef struct { - - FILE * file; - - int char_hack; - int char_line; - int char_column; - bool char_unread; - bool char_first; - - int token_type; - char token_string[PGN_STRING_SIZE]; - int token_length; - int token_line; - int token_column; - bool token_unread; - bool token_first; - - char result[PGN_STRING_SIZE]; - char fen[PGN_STRING_SIZE]; - - int move_line; - int move_column; - int game_nb; -} pgn_t; - -// functions - -extern void pgn_open (pgn_t * pgn, const char file_name[]); -extern void pgn_close (pgn_t * pgn); - -extern bool pgn_next_game (pgn_t * pgn); -extern bool pgn_next_move (pgn_t * pgn, char string[], int size); - -#endif // !defined PGN_H - -// end of pgn.h - + +// pgn.h + +#ifndef PGN_H +#define PGN_H + +// includes + +#include + +#include "util.h" + +// defines + +#define PGN_STRING_SIZE 256 + +// types + +typedef struct { + + FILE * file; + + int char_hack; + int char_line; + int char_column; + bool char_unread; + bool char_first; + + int token_type; + char token_string[PGN_STRING_SIZE]; + int token_length; + int token_line; + int token_column; + bool token_unread; + bool token_first; + + char result[PGN_STRING_SIZE]; + char fen[PGN_STRING_SIZE]; + + int move_line; + int move_column; + int game_nb; +} pgn_t; + +// functions + +extern void pgn_open (pgn_t * pgn, const char file_name[]); +extern void pgn_close (pgn_t * pgn); + +extern bool pgn_next_game (pgn_t * pgn); +extern bool pgn_next_move (pgn_t * pgn, char string[], int size); + +#endif // !defined PGN_H + +// end of pgn.h + diff --git a/piece.c b/piece.c index 82ed76a..f5facf9 100644 --- a/piece.c +++ b/piece.c @@ -1,203 +1,203 @@ - -// piece.c - -// includes - -#include - -#include "colour.h" -#include "piece.h" -#include "util.h" - -// "constants" - -static const uint8 MakePawn[ColourNb] = { PieceNone256, BlackPawn256, WhitePawn256 }; // -BW - -static const uint8 PieceFrom12[12] = { - BlackPawn256, WhitePawn256, - BlackKnight256, WhiteKnight256, - BlackBishop256, WhiteBishop256, - BlackRook256, WhiteRook256, - BlackQueen256, WhiteQueen256, - BlackKing256, WhiteKing256, -}; - -static const char PieceString[12+1] = "pPnNbBrRqQkK"; - -// variables - -static sint8 PieceTo12[256]; - -// functions - -// piece_init() - -void piece_init() { - - int piece; - - for (piece = 0; piece < 256; piece++) PieceTo12[piece] = -1; - - for (piece = 0; piece < 12; piece++) { - PieceTo12[PieceFrom12[piece]] = piece; - } -} - -// piece_is_ok() - -bool piece_is_ok(int piece) { - - if (piece < 0 || piece >= 256) return FALSE; - - if (PieceTo12[piece] < 0) return FALSE; - - return TRUE; -} - -// piece_make_pawn() - -int piece_make_pawn(int colour) { - - ASSERT(colour_is_ok(colour)); - - return MakePawn[colour]; -} - -// piece_pawn_opp() - -int piece_pawn_opp(int piece) { - - ASSERT(piece==BlackPawn256||piece==WhitePawn256); - - return piece ^ 15; -} - -// piece_colour() - -int piece_colour(int piece) { - - ASSERT(piece_is_ok(piece)); - - return piece & 3; -} - -// piece_type() - -int piece_type(int piece) { - - ASSERT(piece_is_ok(piece)); - - return piece & ~3; -} - -// piece_is_pawn() - -bool piece_is_pawn(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & PawnFlags) != 0; -} - -// piece_is_knight() - -bool piece_is_knight(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & KnightFlag) != 0; -} - -// piece_is_bishop() - -bool piece_is_bishop(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & QueenFlags) == BishopFlag; -} - -// piece_is_rook() - -bool piece_is_rook(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & QueenFlags) == RookFlag; -} - -// piece_is_queen() - -bool piece_is_queen(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & QueenFlags) == QueenFlags; -} - -// piece_is_king() - -bool piece_is_king(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & KingFlag) != 0; -} - -// piece_is_slider() - -bool piece_is_slider(int piece) { - - ASSERT(piece_is_ok(piece)); - - return (piece & QueenFlags) != 0; -} - -// piece_to_12() - -int piece_to_12(int piece) { - - ASSERT(piece_is_ok(piece)); - - return PieceTo12[piece]; -} - -// piece_from_12() - -int piece_from_12(int piece) { - - ASSERT(piece>=0&&piece<12); - - return PieceFrom12[piece]; -} - -// piece_to_char() - -int piece_to_char(int piece) { - - ASSERT(piece_is_ok(piece)); - - return PieceString[piece_to_12(piece)]; -} - -// piece_from_char() - -int piece_from_char(int c) { - - const char * ptr; - - ptr = strchr(PieceString,c); - if (ptr == NULL) return PieceNone256; - - return piece_from_12(ptr-PieceString); -} - -// char_is_piece() - -bool char_is_piece(int c) { - - return strchr("PNBRQK",c) != NULL; -} - -// end of piece.cpp - + +// piece.c + +// includes + +#include + +#include "colour.h" +#include "piece.h" +#include "util.h" + +// "constants" + +static const uint8 MakePawn[ColourNb] = { PieceNone256, BlackPawn256, WhitePawn256 }; // -BW + +static const uint8 PieceFrom12[12] = { + BlackPawn256, WhitePawn256, + BlackKnight256, WhiteKnight256, + BlackBishop256, WhiteBishop256, + BlackRook256, WhiteRook256, + BlackQueen256, WhiteQueen256, + BlackKing256, WhiteKing256, +}; + +static const char PieceString[12+1] = "pPnNbBrRqQkK"; + +// variables + +static sint8 PieceTo12[256]; + +// functions + +// piece_init() + +void piece_init() { + + int piece; + + for (piece = 0; piece < 256; piece++) PieceTo12[piece] = -1; + + for (piece = 0; piece < 12; piece++) { + PieceTo12[PieceFrom12[piece]] = piece; + } +} + +// piece_is_ok() + +bool piece_is_ok(int piece) { + + if (piece < 0 || piece >= 256) return FALSE; + + if (PieceTo12[piece] < 0) return FALSE; + + return TRUE; +} + +// piece_make_pawn() + +int piece_make_pawn(int colour) { + + ASSERT(colour_is_ok(colour)); + + return MakePawn[colour]; +} + +// piece_pawn_opp() + +int piece_pawn_opp(int piece) { + + ASSERT(piece==BlackPawn256||piece==WhitePawn256); + + return piece ^ 15; +} + +// piece_colour() + +int piece_colour(int piece) { + + ASSERT(piece_is_ok(piece)); + + return piece & 3; +} + +// piece_type() + +int piece_type(int piece) { + + ASSERT(piece_is_ok(piece)); + + return piece & ~3; +} + +// piece_is_pawn() + +bool piece_is_pawn(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & PawnFlags) != 0; +} + +// piece_is_knight() + +bool piece_is_knight(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & KnightFlag) != 0; +} + +// piece_is_bishop() + +bool piece_is_bishop(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) == BishopFlag; +} + +// piece_is_rook() + +bool piece_is_rook(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) == RookFlag; +} + +// piece_is_queen() + +bool piece_is_queen(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) == QueenFlags; +} + +// piece_is_king() + +bool piece_is_king(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & KingFlag) != 0; +} + +// piece_is_slider() + +bool piece_is_slider(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) != 0; +} + +// piece_to_12() + +int piece_to_12(int piece) { + + ASSERT(piece_is_ok(piece)); + + return PieceTo12[piece]; +} + +// piece_from_12() + +int piece_from_12(int piece) { + + ASSERT(piece>=0&&piece<12); + + return PieceFrom12[piece]; +} + +// piece_to_char() + +int piece_to_char(int piece) { + + ASSERT(piece_is_ok(piece)); + + return PieceString[piece_to_12(piece)]; +} + +// piece_from_char() + +int piece_from_char(int c) { + + const char * ptr; + + ptr = strchr(PieceString,c); + if (ptr == NULL) return PieceNone256; + + return piece_from_12(ptr-PieceString); +} + +// char_is_piece() + +bool char_is_piece(int c) { + + return strchr("PNBRQK",c) != NULL; +} + +// end of piece.cpp + diff --git a/piece.h b/piece.h index f060cb6..f1bebfd 100644 --- a/piece.h +++ b/piece.h @@ -1,92 +1,92 @@ - -// piece.h - -#ifndef PIECE_H -#define PIECE_H - -// includes - -#include "colour.h" -#include "util.h" - -// defines - -#define BlackPawnFlag (1 << 2) -#define WhitePawnFlag (1 << 3) -#define KnightFlag (1 << 4) -#define BishopFlag (1 << 5) -#define RookFlag (1 << 6) -#define KingFlag (1 << 7) - -#define PawnFlags (BlackPawnFlag | WhitePawnFlag) -#define QueenFlags (BishopFlag | RookFlag) - -#define PieceNone64 (0) -#define BlackPawn64 (BlackPawnFlag) -#define WhitePawn64 (WhitePawnFlag) -#define Knight64 (KnightFlag) -#define Bishop64 (BishopFlag) -#define Rook64 (RookFlag) -#define Queen64 (QueenFlags) -#define King64 (KingFlag) - -#define PieceNone256 (0) -#define BlackPawn256 (BlackPawn64 | Black) -#define WhitePawn256 (WhitePawn64 | White) -#define BlackKnight256 (Knight64 | Black) -#define WhiteKnight256 (Knight64 | White) -#define BlackBishop256 (Bishop64 | Black) -#define WhiteBishop256 (Bishop64 | White) -#define BlackRook256 (Rook64 | Black) -#define WhiteRook256 (Rook64 | White) -#define BlackQueen256 (Queen64 | Black) -#define WhiteQueen256 (Queen64 | White) -#define BlackKing256 (King64 | Black) -#define WhiteKing256 (King64 | White) - -#define BlackPawn12 (0) -#define WhitePawn12 (1) -#define BlackKnight12 (2) -#define WhiteKnight12 (3) -#define BlackBishop12 (4) -#define WhiteBishop12 (5) -#define BlackRook12 (6) -#define WhiteRook12 (7) -#define BlackQueen12 (8) -#define WhiteQueen12 (9) -#define BlackKing12 (10) -#define WhiteKing12 (11) - -// functions - -extern void piece_init (); - -extern bool piece_is_ok (int piece); - -extern int piece_make_pawn (int colour); -extern int piece_pawn_opp (int piece); - -extern int piece_colour (int piece); -extern int piece_type (int piece); - -extern bool piece_is_pawn (int piece); -extern bool piece_is_knight (int piece); -extern bool piece_is_bishop (int piece); -extern bool piece_is_rook (int piece); -extern bool piece_is_queen (int piece); -extern bool piece_is_king (int piece); - -extern bool piece_is_slider (int piece); - -extern int piece_to_12 (int piece); -extern int piece_from_12 (int piece); - -extern int piece_to_char (int piece); -extern int piece_from_char (int c); - -extern bool char_is_piece (int c); - -#endif // !defined PIECE_H - -// end of piece.h - + +// piece.h + +#ifndef PIECE_H +#define PIECE_H + +// includes + +#include "colour.h" +#include "util.h" + +// defines + +#define BlackPawnFlag (1 << 2) +#define WhitePawnFlag (1 << 3) +#define KnightFlag (1 << 4) +#define BishopFlag (1 << 5) +#define RookFlag (1 << 6) +#define KingFlag (1 << 7) + +#define PawnFlags (BlackPawnFlag | WhitePawnFlag) +#define QueenFlags (BishopFlag | RookFlag) + +#define PieceNone64 (0) +#define BlackPawn64 (BlackPawnFlag) +#define WhitePawn64 (WhitePawnFlag) +#define Knight64 (KnightFlag) +#define Bishop64 (BishopFlag) +#define Rook64 (RookFlag) +#define Queen64 (QueenFlags) +#define King64 (KingFlag) + +#define PieceNone256 (0) +#define BlackPawn256 (BlackPawn64 | Black) +#define WhitePawn256 (WhitePawn64 | White) +#define BlackKnight256 (Knight64 | Black) +#define WhiteKnight256 (Knight64 | White) +#define BlackBishop256 (Bishop64 | Black) +#define WhiteBishop256 (Bishop64 | White) +#define BlackRook256 (Rook64 | Black) +#define WhiteRook256 (Rook64 | White) +#define BlackQueen256 (Queen64 | Black) +#define WhiteQueen256 (Queen64 | White) +#define BlackKing256 (King64 | Black) +#define WhiteKing256 (King64 | White) + +#define BlackPawn12 (0) +#define WhitePawn12 (1) +#define BlackKnight12 (2) +#define WhiteKnight12 (3) +#define BlackBishop12 (4) +#define WhiteBishop12 (5) +#define BlackRook12 (6) +#define WhiteRook12 (7) +#define BlackQueen12 (8) +#define WhiteQueen12 (9) +#define BlackKing12 (10) +#define WhiteKing12 (11) + +// functions + +extern void piece_init (); + +extern bool piece_is_ok (int piece); + +extern int piece_make_pawn (int colour); +extern int piece_pawn_opp (int piece); + +extern int piece_colour (int piece); +extern int piece_type (int piece); + +extern bool piece_is_pawn (int piece); +extern bool piece_is_knight (int piece); +extern bool piece_is_bishop (int piece); +extern bool piece_is_rook (int piece); +extern bool piece_is_queen (int piece); +extern bool piece_is_king (int piece); + +extern bool piece_is_slider (int piece); + +extern int piece_to_12 (int piece); +extern int piece_from_12 (int piece); + +extern int piece_to_char (int piece); +extern int piece_from_char (int c); + +extern bool char_is_piece (int c); + +#endif // !defined PIECE_H + +// end of piece.h + diff --git a/pipex_posix.c b/pipex_posix.c index 3301d95..9ce06f3 100644 --- a/pipex_posix.c +++ b/pipex_posix.c @@ -9,10 +9,6 @@ #include #include "pipex.h" -// constants - -static const unsigned int StringSize = 4096; - // prototypes static void my_close(int fd); diff --git a/polyglot.spec b/polyglot.spec index 6deb2e7..8643a3e 100644 --- a/polyglot.spec +++ b/polyglot.spec @@ -1,6 +1,6 @@ Summary: A Winboard protocol to UCI protocol adapter Name: polyglot -Version: 1.4.61b +Version: 1.4.63b Release: 1 License: GPL Group: Amusement/Games diff --git a/random.c b/random.c index b687231..e9557c7 100644 --- a/random.c +++ b/random.c @@ -1,231 +1,231 @@ - -// random.c - -// includes - -#include "random.h" -#include "util.h" - -// "constants" - -const uint64 Random64[RandomNb] = { - U64(0x9D39247E33776D41), U64(0x2AF7398005AAA5C7), U64(0x44DB015024623547), U64(0x9C15F73E62A76AE2), - U64(0x75834465489C0C89), U64(0x3290AC3A203001BF), U64(0x0FBBAD1F61042279), U64(0xE83A908FF2FB60CA), - U64(0x0D7E765D58755C10), U64(0x1A083822CEAFE02D), U64(0x9605D5F0E25EC3B0), U64(0xD021FF5CD13A2ED5), - U64(0x40BDF15D4A672E32), U64(0x011355146FD56395), U64(0x5DB4832046F3D9E5), U64(0x239F8B2D7FF719CC), - U64(0x05D1A1AE85B49AA1), U64(0x679F848F6E8FC971), U64(0x7449BBFF801FED0B), U64(0x7D11CDB1C3B7ADF0), - U64(0x82C7709E781EB7CC), U64(0xF3218F1C9510786C), U64(0x331478F3AF51BBE6), U64(0x4BB38DE5E7219443), - U64(0xAA649C6EBCFD50FC), U64(0x8DBD98A352AFD40B), U64(0x87D2074B81D79217), U64(0x19F3C751D3E92AE1), - U64(0xB4AB30F062B19ABF), U64(0x7B0500AC42047AC4), U64(0xC9452CA81A09D85D), U64(0x24AA6C514DA27500), - U64(0x4C9F34427501B447), U64(0x14A68FD73C910841), U64(0xA71B9B83461CBD93), U64(0x03488B95B0F1850F), - U64(0x637B2B34FF93C040), U64(0x09D1BC9A3DD90A94), U64(0x3575668334A1DD3B), U64(0x735E2B97A4C45A23), - U64(0x18727070F1BD400B), U64(0x1FCBACD259BF02E7), U64(0xD310A7C2CE9B6555), U64(0xBF983FE0FE5D8244), - U64(0x9F74D14F7454A824), U64(0x51EBDC4AB9BA3035), U64(0x5C82C505DB9AB0FA), U64(0xFCF7FE8A3430B241), - U64(0x3253A729B9BA3DDE), U64(0x8C74C368081B3075), U64(0xB9BC6C87167C33E7), U64(0x7EF48F2B83024E20), - U64(0x11D505D4C351BD7F), U64(0x6568FCA92C76A243), U64(0x4DE0B0F40F32A7B8), U64(0x96D693460CC37E5D), - U64(0x42E240CB63689F2F), U64(0x6D2BDCDAE2919661), U64(0x42880B0236E4D951), U64(0x5F0F4A5898171BB6), - U64(0x39F890F579F92F88), U64(0x93C5B5F47356388B), U64(0x63DC359D8D231B78), U64(0xEC16CA8AEA98AD76), - U64(0x5355F900C2A82DC7), U64(0x07FB9F855A997142), U64(0x5093417AA8A7ED5E), U64(0x7BCBC38DA25A7F3C), - U64(0x19FC8A768CF4B6D4), U64(0x637A7780DECFC0D9), U64(0x8249A47AEE0E41F7), U64(0x79AD695501E7D1E8), - U64(0x14ACBAF4777D5776), U64(0xF145B6BECCDEA195), U64(0xDABF2AC8201752FC), U64(0x24C3C94DF9C8D3F6), - U64(0xBB6E2924F03912EA), U64(0x0CE26C0B95C980D9), U64(0xA49CD132BFBF7CC4), U64(0xE99D662AF4243939), - U64(0x27E6AD7891165C3F), U64(0x8535F040B9744FF1), U64(0x54B3F4FA5F40D873), U64(0x72B12C32127FED2B), - U64(0xEE954D3C7B411F47), U64(0x9A85AC909A24EAA1), U64(0x70AC4CD9F04F21F5), U64(0xF9B89D3E99A075C2), - U64(0x87B3E2B2B5C907B1), U64(0xA366E5B8C54F48B8), U64(0xAE4A9346CC3F7CF2), U64(0x1920C04D47267BBD), - U64(0x87BF02C6B49E2AE9), U64(0x092237AC237F3859), U64(0xFF07F64EF8ED14D0), U64(0x8DE8DCA9F03CC54E), - U64(0x9C1633264DB49C89), U64(0xB3F22C3D0B0B38ED), U64(0x390E5FB44D01144B), U64(0x5BFEA5B4712768E9), - U64(0x1E1032911FA78984), U64(0x9A74ACB964E78CB3), U64(0x4F80F7A035DAFB04), U64(0x6304D09A0B3738C4), - U64(0x2171E64683023A08), U64(0x5B9B63EB9CEFF80C), U64(0x506AACF489889342), U64(0x1881AFC9A3A701D6), - U64(0x6503080440750644), U64(0xDFD395339CDBF4A7), U64(0xEF927DBCF00C20F2), U64(0x7B32F7D1E03680EC), - U64(0xB9FD7620E7316243), U64(0x05A7E8A57DB91B77), U64(0xB5889C6E15630A75), U64(0x4A750A09CE9573F7), - U64(0xCF464CEC899A2F8A), U64(0xF538639CE705B824), U64(0x3C79A0FF5580EF7F), U64(0xEDE6C87F8477609D), - U64(0x799E81F05BC93F31), U64(0x86536B8CF3428A8C), U64(0x97D7374C60087B73), U64(0xA246637CFF328532), - U64(0x043FCAE60CC0EBA0), U64(0x920E449535DD359E), U64(0x70EB093B15B290CC), U64(0x73A1921916591CBD), - U64(0x56436C9FE1A1AA8D), U64(0xEFAC4B70633B8F81), U64(0xBB215798D45DF7AF), U64(0x45F20042F24F1768), - U64(0x930F80F4E8EB7462), U64(0xFF6712FFCFD75EA1), U64(0xAE623FD67468AA70), U64(0xDD2C5BC84BC8D8FC), - U64(0x7EED120D54CF2DD9), U64(0x22FE545401165F1C), U64(0xC91800E98FB99929), U64(0x808BD68E6AC10365), - U64(0xDEC468145B7605F6), U64(0x1BEDE3A3AEF53302), U64(0x43539603D6C55602), U64(0xAA969B5C691CCB7A), - U64(0xA87832D392EFEE56), U64(0x65942C7B3C7E11AE), U64(0xDED2D633CAD004F6), U64(0x21F08570F420E565), - U64(0xB415938D7DA94E3C), U64(0x91B859E59ECB6350), U64(0x10CFF333E0ED804A), U64(0x28AED140BE0BB7DD), - U64(0xC5CC1D89724FA456), U64(0x5648F680F11A2741), U64(0x2D255069F0B7DAB3), U64(0x9BC5A38EF729ABD4), - U64(0xEF2F054308F6A2BC), U64(0xAF2042F5CC5C2858), U64(0x480412BAB7F5BE2A), U64(0xAEF3AF4A563DFE43), - U64(0x19AFE59AE451497F), U64(0x52593803DFF1E840), U64(0xF4F076E65F2CE6F0), U64(0x11379625747D5AF3), - U64(0xBCE5D2248682C115), U64(0x9DA4243DE836994F), U64(0x066F70B33FE09017), U64(0x4DC4DE189B671A1C), - U64(0x51039AB7712457C3), U64(0xC07A3F80C31FB4B4), U64(0xB46EE9C5E64A6E7C), U64(0xB3819A42ABE61C87), - U64(0x21A007933A522A20), U64(0x2DF16F761598AA4F), U64(0x763C4A1371B368FD), U64(0xF793C46702E086A0), - U64(0xD7288E012AEB8D31), U64(0xDE336A2A4BC1C44B), U64(0x0BF692B38D079F23), U64(0x2C604A7A177326B3), - U64(0x4850E73E03EB6064), U64(0xCFC447F1E53C8E1B), U64(0xB05CA3F564268D99), U64(0x9AE182C8BC9474E8), - U64(0xA4FC4BD4FC5558CA), U64(0xE755178D58FC4E76), U64(0x69B97DB1A4C03DFE), U64(0xF9B5B7C4ACC67C96), - U64(0xFC6A82D64B8655FB), U64(0x9C684CB6C4D24417), U64(0x8EC97D2917456ED0), U64(0x6703DF9D2924E97E), - U64(0xC547F57E42A7444E), U64(0x78E37644E7CAD29E), U64(0xFE9A44E9362F05FA), U64(0x08BD35CC38336615), - U64(0x9315E5EB3A129ACE), U64(0x94061B871E04DF75), U64(0xDF1D9F9D784BA010), U64(0x3BBA57B68871B59D), - U64(0xD2B7ADEEDED1F73F), U64(0xF7A255D83BC373F8), U64(0xD7F4F2448C0CEB81), U64(0xD95BE88CD210FFA7), - U64(0x336F52F8FF4728E7), U64(0xA74049DAC312AC71), U64(0xA2F61BB6E437FDB5), U64(0x4F2A5CB07F6A35B3), - U64(0x87D380BDA5BF7859), U64(0x16B9F7E06C453A21), U64(0x7BA2484C8A0FD54E), U64(0xF3A678CAD9A2E38C), - U64(0x39B0BF7DDE437BA2), U64(0xFCAF55C1BF8A4424), U64(0x18FCF680573FA594), U64(0x4C0563B89F495AC3), - U64(0x40E087931A00930D), U64(0x8CFFA9412EB642C1), U64(0x68CA39053261169F), U64(0x7A1EE967D27579E2), - U64(0x9D1D60E5076F5B6F), U64(0x3810E399B6F65BA2), U64(0x32095B6D4AB5F9B1), U64(0x35CAB62109DD038A), - U64(0xA90B24499FCFAFB1), U64(0x77A225A07CC2C6BD), U64(0x513E5E634C70E331), U64(0x4361C0CA3F692F12), - U64(0xD941ACA44B20A45B), U64(0x528F7C8602C5807B), U64(0x52AB92BEB9613989), U64(0x9D1DFA2EFC557F73), - U64(0x722FF175F572C348), U64(0x1D1260A51107FE97), U64(0x7A249A57EC0C9BA2), U64(0x04208FE9E8F7F2D6), - U64(0x5A110C6058B920A0), U64(0x0CD9A497658A5698), U64(0x56FD23C8F9715A4C), U64(0x284C847B9D887AAE), - U64(0x04FEABFBBDB619CB), U64(0x742E1E651C60BA83), U64(0x9A9632E65904AD3C), U64(0x881B82A13B51B9E2), - U64(0x506E6744CD974924), U64(0xB0183DB56FFC6A79), U64(0x0ED9B915C66ED37E), U64(0x5E11E86D5873D484), - U64(0xF678647E3519AC6E), U64(0x1B85D488D0F20CC5), U64(0xDAB9FE6525D89021), U64(0x0D151D86ADB73615), - U64(0xA865A54EDCC0F019), U64(0x93C42566AEF98FFB), U64(0x99E7AFEABE000731), U64(0x48CBFF086DDF285A), - U64(0x7F9B6AF1EBF78BAF), U64(0x58627E1A149BBA21), U64(0x2CD16E2ABD791E33), U64(0xD363EFF5F0977996), - U64(0x0CE2A38C344A6EED), U64(0x1A804AADB9CFA741), U64(0x907F30421D78C5DE), U64(0x501F65EDB3034D07), - U64(0x37624AE5A48FA6E9), U64(0x957BAF61700CFF4E), U64(0x3A6C27934E31188A), U64(0xD49503536ABCA345), - U64(0x088E049589C432E0), U64(0xF943AEE7FEBF21B8), U64(0x6C3B8E3E336139D3), U64(0x364F6FFA464EE52E), - U64(0xD60F6DCEDC314222), U64(0x56963B0DCA418FC0), U64(0x16F50EDF91E513AF), U64(0xEF1955914B609F93), - U64(0x565601C0364E3228), U64(0xECB53939887E8175), U64(0xBAC7A9A18531294B), U64(0xB344C470397BBA52), - U64(0x65D34954DAF3CEBD), U64(0xB4B81B3FA97511E2), U64(0xB422061193D6F6A7), U64(0x071582401C38434D), - U64(0x7A13F18BBEDC4FF5), U64(0xBC4097B116C524D2), U64(0x59B97885E2F2EA28), U64(0x99170A5DC3115544), - U64(0x6F423357E7C6A9F9), U64(0x325928EE6E6F8794), U64(0xD0E4366228B03343), U64(0x565C31F7DE89EA27), - U64(0x30F5611484119414), U64(0xD873DB391292ED4F), U64(0x7BD94E1D8E17DEBC), U64(0xC7D9F16864A76E94), - U64(0x947AE053EE56E63C), U64(0xC8C93882F9475F5F), U64(0x3A9BF55BA91F81CA), U64(0xD9A11FBB3D9808E4), - U64(0x0FD22063EDC29FCA), U64(0xB3F256D8ACA0B0B9), U64(0xB03031A8B4516E84), U64(0x35DD37D5871448AF), - U64(0xE9F6082B05542E4E), U64(0xEBFAFA33D7254B59), U64(0x9255ABB50D532280), U64(0xB9AB4CE57F2D34F3), - U64(0x693501D628297551), U64(0xC62C58F97DD949BF), U64(0xCD454F8F19C5126A), U64(0xBBE83F4ECC2BDECB), - U64(0xDC842B7E2819E230), U64(0xBA89142E007503B8), U64(0xA3BC941D0A5061CB), U64(0xE9F6760E32CD8021), - U64(0x09C7E552BC76492F), U64(0x852F54934DA55CC9), U64(0x8107FCCF064FCF56), U64(0x098954D51FFF6580), - U64(0x23B70EDB1955C4BF), U64(0xC330DE426430F69D), U64(0x4715ED43E8A45C0A), U64(0xA8D7E4DAB780A08D), - U64(0x0572B974F03CE0BB), U64(0xB57D2E985E1419C7), U64(0xE8D9ECBE2CF3D73F), U64(0x2FE4B17170E59750), - U64(0x11317BA87905E790), U64(0x7FBF21EC8A1F45EC), U64(0x1725CABFCB045B00), U64(0x964E915CD5E2B207), - U64(0x3E2B8BCBF016D66D), U64(0xBE7444E39328A0AC), U64(0xF85B2B4FBCDE44B7), U64(0x49353FEA39BA63B1), - U64(0x1DD01AAFCD53486A), U64(0x1FCA8A92FD719F85), U64(0xFC7C95D827357AFA), U64(0x18A6A990C8B35EBD), - U64(0xCCCB7005C6B9C28D), U64(0x3BDBB92C43B17F26), U64(0xAA70B5B4F89695A2), U64(0xE94C39A54A98307F), - U64(0xB7A0B174CFF6F36E), U64(0xD4DBA84729AF48AD), U64(0x2E18BC1AD9704A68), U64(0x2DE0966DAF2F8B1C), - U64(0xB9C11D5B1E43A07E), U64(0x64972D68DEE33360), U64(0x94628D38D0C20584), U64(0xDBC0D2B6AB90A559), - U64(0xD2733C4335C6A72F), U64(0x7E75D99D94A70F4D), U64(0x6CED1983376FA72B), U64(0x97FCAACBF030BC24), - U64(0x7B77497B32503B12), U64(0x8547EDDFB81CCB94), U64(0x79999CDFF70902CB), U64(0xCFFE1939438E9B24), - U64(0x829626E3892D95D7), U64(0x92FAE24291F2B3F1), U64(0x63E22C147B9C3403), U64(0xC678B6D860284A1C), - U64(0x5873888850659AE7), U64(0x0981DCD296A8736D), U64(0x9F65789A6509A440), U64(0x9FF38FED72E9052F), - U64(0xE479EE5B9930578C), U64(0xE7F28ECD2D49EECD), U64(0x56C074A581EA17FE), U64(0x5544F7D774B14AEF), - U64(0x7B3F0195FC6F290F), U64(0x12153635B2C0CF57), U64(0x7F5126DBBA5E0CA7), U64(0x7A76956C3EAFB413), - U64(0x3D5774A11D31AB39), U64(0x8A1B083821F40CB4), U64(0x7B4A38E32537DF62), U64(0x950113646D1D6E03), - U64(0x4DA8979A0041E8A9), U64(0x3BC36E078F7515D7), U64(0x5D0A12F27AD310D1), U64(0x7F9D1A2E1EBE1327), - U64(0xDA3A361B1C5157B1), U64(0xDCDD7D20903D0C25), U64(0x36833336D068F707), U64(0xCE68341F79893389), - U64(0xAB9090168DD05F34), U64(0x43954B3252DC25E5), U64(0xB438C2B67F98E5E9), U64(0x10DCD78E3851A492), - U64(0xDBC27AB5447822BF), U64(0x9B3CDB65F82CA382), U64(0xB67B7896167B4C84), U64(0xBFCED1B0048EAC50), - U64(0xA9119B60369FFEBD), U64(0x1FFF7AC80904BF45), U64(0xAC12FB171817EEE7), U64(0xAF08DA9177DDA93D), - U64(0x1B0CAB936E65C744), U64(0xB559EB1D04E5E932), U64(0xC37B45B3F8D6F2BA), U64(0xC3A9DC228CAAC9E9), - U64(0xF3B8B6675A6507FF), U64(0x9FC477DE4ED681DA), U64(0x67378D8ECCEF96CB), U64(0x6DD856D94D259236), - U64(0xA319CE15B0B4DB31), U64(0x073973751F12DD5E), U64(0x8A8E849EB32781A5), U64(0xE1925C71285279F5), - U64(0x74C04BF1790C0EFE), U64(0x4DDA48153C94938A), U64(0x9D266D6A1CC0542C), U64(0x7440FB816508C4FE), - U64(0x13328503DF48229F), U64(0xD6BF7BAEE43CAC40), U64(0x4838D65F6EF6748F), U64(0x1E152328F3318DEA), - U64(0x8F8419A348F296BF), U64(0x72C8834A5957B511), U64(0xD7A023A73260B45C), U64(0x94EBC8ABCFB56DAE), - U64(0x9FC10D0F989993E0), U64(0xDE68A2355B93CAE6), U64(0xA44CFE79AE538BBE), U64(0x9D1D84FCCE371425), - U64(0x51D2B1AB2DDFB636), U64(0x2FD7E4B9E72CD38C), U64(0x65CA5B96B7552210), U64(0xDD69A0D8AB3B546D), - U64(0x604D51B25FBF70E2), U64(0x73AA8A564FB7AC9E), U64(0x1A8C1E992B941148), U64(0xAAC40A2703D9BEA0), - U64(0x764DBEAE7FA4F3A6), U64(0x1E99B96E70A9BE8B), U64(0x2C5E9DEB57EF4743), U64(0x3A938FEE32D29981), - U64(0x26E6DB8FFDF5ADFE), U64(0x469356C504EC9F9D), U64(0xC8763C5B08D1908C), U64(0x3F6C6AF859D80055), - U64(0x7F7CC39420A3A545), U64(0x9BFB227EBDF4C5CE), U64(0x89039D79D6FC5C5C), U64(0x8FE88B57305E2AB6), - U64(0xA09E8C8C35AB96DE), U64(0xFA7E393983325753), U64(0xD6B6D0ECC617C699), U64(0xDFEA21EA9E7557E3), - U64(0xB67C1FA481680AF8), U64(0xCA1E3785A9E724E5), U64(0x1CFC8BED0D681639), U64(0xD18D8549D140CAEA), - U64(0x4ED0FE7E9DC91335), U64(0xE4DBF0634473F5D2), U64(0x1761F93A44D5AEFE), U64(0x53898E4C3910DA55), - U64(0x734DE8181F6EC39A), U64(0x2680B122BAA28D97), U64(0x298AF231C85BAFAB), U64(0x7983EED3740847D5), - U64(0x66C1A2A1A60CD889), U64(0x9E17E49642A3E4C1), U64(0xEDB454E7BADC0805), U64(0x50B704CAB602C329), - U64(0x4CC317FB9CDDD023), U64(0x66B4835D9EAFEA22), U64(0x219B97E26FFC81BD), U64(0x261E4E4C0A333A9D), - U64(0x1FE2CCA76517DB90), U64(0xD7504DFA8816EDBB), U64(0xB9571FA04DC089C8), U64(0x1DDC0325259B27DE), - U64(0xCF3F4688801EB9AA), U64(0xF4F5D05C10CAB243), U64(0x38B6525C21A42B0E), U64(0x36F60E2BA4FA6800), - U64(0xEB3593803173E0CE), U64(0x9C4CD6257C5A3603), U64(0xAF0C317D32ADAA8A), U64(0x258E5A80C7204C4B), - U64(0x8B889D624D44885D), U64(0xF4D14597E660F855), U64(0xD4347F66EC8941C3), U64(0xE699ED85B0DFB40D), - U64(0x2472F6207C2D0484), U64(0xC2A1E7B5B459AEB5), U64(0xAB4F6451CC1D45EC), U64(0x63767572AE3D6174), - U64(0xA59E0BD101731A28), U64(0x116D0016CB948F09), U64(0x2CF9C8CA052F6E9F), U64(0x0B090A7560A968E3), - U64(0xABEEDDB2DDE06FF1), U64(0x58EFC10B06A2068D), U64(0xC6E57A78FBD986E0), U64(0x2EAB8CA63CE802D7), - U64(0x14A195640116F336), U64(0x7C0828DD624EC390), U64(0xD74BBE77E6116AC7), U64(0x804456AF10F5FB53), - U64(0xEBE9EA2ADF4321C7), U64(0x03219A39EE587A30), U64(0x49787FEF17AF9924), U64(0xA1E9300CD8520548), - U64(0x5B45E522E4B1B4EF), U64(0xB49C3B3995091A36), U64(0xD4490AD526F14431), U64(0x12A8F216AF9418C2), - U64(0x001F837CC7350524), U64(0x1877B51E57A764D5), U64(0xA2853B80F17F58EE), U64(0x993E1DE72D36D310), - U64(0xB3598080CE64A656), U64(0x252F59CF0D9F04BB), U64(0xD23C8E176D113600), U64(0x1BDA0492E7E4586E), - U64(0x21E0BD5026C619BF), U64(0x3B097ADAF088F94E), U64(0x8D14DEDB30BE846E), U64(0xF95CFFA23AF5F6F4), - U64(0x3871700761B3F743), U64(0xCA672B91E9E4FA16), U64(0x64C8E531BFF53B55), U64(0x241260ED4AD1E87D), - U64(0x106C09B972D2E822), U64(0x7FBA195410E5CA30), U64(0x7884D9BC6CB569D8), U64(0x0647DFEDCD894A29), - U64(0x63573FF03E224774), U64(0x4FC8E9560F91B123), U64(0x1DB956E450275779), U64(0xB8D91274B9E9D4FB), - U64(0xA2EBEE47E2FBFCE1), U64(0xD9F1F30CCD97FB09), U64(0xEFED53D75FD64E6B), U64(0x2E6D02C36017F67F), - U64(0xA9AA4D20DB084E9B), U64(0xB64BE8D8B25396C1), U64(0x70CB6AF7C2D5BCF0), U64(0x98F076A4F7A2322E), - U64(0xBF84470805E69B5F), U64(0x94C3251F06F90CF3), U64(0x3E003E616A6591E9), U64(0xB925A6CD0421AFF3), - U64(0x61BDD1307C66E300), U64(0xBF8D5108E27E0D48), U64(0x240AB57A8B888B20), U64(0xFC87614BAF287E07), - U64(0xEF02CDD06FFDB432), U64(0xA1082C0466DF6C0A), U64(0x8215E577001332C8), U64(0xD39BB9C3A48DB6CF), - U64(0x2738259634305C14), U64(0x61CF4F94C97DF93D), U64(0x1B6BACA2AE4E125B), U64(0x758F450C88572E0B), - U64(0x959F587D507A8359), U64(0xB063E962E045F54D), U64(0x60E8ED72C0DFF5D1), U64(0x7B64978555326F9F), - U64(0xFD080D236DA814BA), U64(0x8C90FD9B083F4558), U64(0x106F72FE81E2C590), U64(0x7976033A39F7D952), - U64(0xA4EC0132764CA04B), U64(0x733EA705FAE4FA77), U64(0xB4D8F77BC3E56167), U64(0x9E21F4F903B33FD9), - U64(0x9D765E419FB69F6D), U64(0xD30C088BA61EA5EF), U64(0x5D94337FBFAF7F5B), U64(0x1A4E4822EB4D7A59), - U64(0x6FFE73E81B637FB3), U64(0xDDF957BC36D8B9CA), U64(0x64D0E29EEA8838B3), U64(0x08DD9BDFD96B9F63), - U64(0x087E79E5A57D1D13), U64(0xE328E230E3E2B3FB), U64(0x1C2559E30F0946BE), U64(0x720BF5F26F4D2EAA), - U64(0xB0774D261CC609DB), U64(0x443F64EC5A371195), U64(0x4112CF68649A260E), U64(0xD813F2FAB7F5C5CA), - U64(0x660D3257380841EE), U64(0x59AC2C7873F910A3), U64(0xE846963877671A17), U64(0x93B633ABFA3469F8), - U64(0xC0C0F5A60EF4CDCF), U64(0xCAF21ECD4377B28C), U64(0x57277707199B8175), U64(0x506C11B9D90E8B1D), - U64(0xD83CC2687A19255F), U64(0x4A29C6465A314CD1), U64(0xED2DF21216235097), U64(0xB5635C95FF7296E2), - U64(0x22AF003AB672E811), U64(0x52E762596BF68235), U64(0x9AEBA33AC6ECC6B0), U64(0x944F6DE09134DFB6), - U64(0x6C47BEC883A7DE39), U64(0x6AD047C430A12104), U64(0xA5B1CFDBA0AB4067), U64(0x7C45D833AFF07862), - U64(0x5092EF950A16DA0B), U64(0x9338E69C052B8E7B), U64(0x455A4B4CFE30E3F5), U64(0x6B02E63195AD0CF8), - U64(0x6B17B224BAD6BF27), U64(0xD1E0CCD25BB9C169), U64(0xDE0C89A556B9AE70), U64(0x50065E535A213CF6), - U64(0x9C1169FA2777B874), U64(0x78EDEFD694AF1EED), U64(0x6DC93D9526A50E68), U64(0xEE97F453F06791ED), - U64(0x32AB0EDB696703D3), U64(0x3A6853C7E70757A7), U64(0x31865CED6120F37D), U64(0x67FEF95D92607890), - U64(0x1F2B1D1F15F6DC9C), U64(0xB69E38A8965C6B65), U64(0xAA9119FF184CCCF4), U64(0xF43C732873F24C13), - U64(0xFB4A3D794A9A80D2), U64(0x3550C2321FD6109C), U64(0x371F77E76BB8417E), U64(0x6BFA9AAE5EC05779), - U64(0xCD04F3FF001A4778), U64(0xE3273522064480CA), U64(0x9F91508BFFCFC14A), U64(0x049A7F41061A9E60), - U64(0xFCB6BE43A9F2FE9B), U64(0x08DE8A1C7797DA9B), U64(0x8F9887E6078735A1), U64(0xB5B4071DBFC73A66), - U64(0x230E343DFBA08D33), U64(0x43ED7F5A0FAE657D), U64(0x3A88A0FBBCB05C63), U64(0x21874B8B4D2DBC4F), - U64(0x1BDEA12E35F6A8C9), U64(0x53C065C6C8E63528), U64(0xE34A1D250E7A8D6B), U64(0xD6B04D3B7651DD7E), - U64(0x5E90277E7CB39E2D), U64(0x2C046F22062DC67D), U64(0xB10BB459132D0A26), U64(0x3FA9DDFB67E2F199), - U64(0x0E09B88E1914F7AF), U64(0x10E8B35AF3EEAB37), U64(0x9EEDECA8E272B933), U64(0xD4C718BC4AE8AE5F), - U64(0x81536D601170FC20), U64(0x91B534F885818A06), U64(0xEC8177F83F900978), U64(0x190E714FADA5156E), - U64(0xB592BF39B0364963), U64(0x89C350C893AE7DC1), U64(0xAC042E70F8B383F2), U64(0xB49B52E587A1EE60), - U64(0xFB152FE3FF26DA89), U64(0x3E666E6F69AE2C15), U64(0x3B544EBE544C19F9), U64(0xE805A1E290CF2456), - U64(0x24B33C9D7ED25117), U64(0xE74733427B72F0C1), U64(0x0A804D18B7097475), U64(0x57E3306D881EDB4F), - U64(0x4AE7D6A36EB5DBCB), U64(0x2D8D5432157064C8), U64(0xD1E649DE1E7F268B), U64(0x8A328A1CEDFE552C), - U64(0x07A3AEC79624C7DA), U64(0x84547DDC3E203C94), U64(0x990A98FD5071D263), U64(0x1A4FF12616EEFC89), - U64(0xF6F7FD1431714200), U64(0x30C05B1BA332F41C), U64(0x8D2636B81555A786), U64(0x46C9FEB55D120902), - U64(0xCCEC0A73B49C9921), U64(0x4E9D2827355FC492), U64(0x19EBB029435DCB0F), U64(0x4659D2B743848A2C), - U64(0x963EF2C96B33BE31), U64(0x74F85198B05A2E7D), U64(0x5A0F544DD2B1FB18), U64(0x03727073C2E134B1), - U64(0xC7F6AA2DE59AEA61), U64(0x352787BAA0D7C22F), U64(0x9853EAB63B5E0B35), U64(0xABBDCDD7ED5C0860), - U64(0xCF05DAF5AC8D77B0), U64(0x49CAD48CEBF4A71E), U64(0x7A4C10EC2158C4A6), U64(0xD9E92AA246BF719E), - U64(0x13AE978D09FE5557), U64(0x730499AF921549FF), U64(0x4E4B705B92903BA4), U64(0xFF577222C14F0A3A), - U64(0x55B6344CF97AAFAE), U64(0xB862225B055B6960), U64(0xCAC09AFBDDD2CDB4), U64(0xDAF8E9829FE96B5F), - U64(0xB5FDFC5D3132C498), U64(0x310CB380DB6F7503), U64(0xE87FBB46217A360E), U64(0x2102AE466EBB1148), - U64(0xF8549E1A3AA5E00D), U64(0x07A69AFDCC42261A), U64(0xC4C118BFE78FEAAE), U64(0xF9F4892ED96BD438), - U64(0x1AF3DBE25D8F45DA), U64(0xF5B4B0B0D2DEEEB4), U64(0x962ACEEFA82E1C84), U64(0x046E3ECAAF453CE9), - U64(0xF05D129681949A4C), U64(0x964781CE734B3C84), U64(0x9C2ED44081CE5FBD), U64(0x522E23F3925E319E), - U64(0x177E00F9FC32F791), U64(0x2BC60A63A6F3B3F2), U64(0x222BBFAE61725606), U64(0x486289DDCC3D6780), - U64(0x7DC7785B8EFDFC80), U64(0x8AF38731C02BA980), U64(0x1FAB64EA29A2DDF7), U64(0xE4D9429322CD065A), - U64(0x9DA058C67844F20C), U64(0x24C0E332B70019B0), U64(0x233003B5A6CFE6AD), U64(0xD586BD01C5C217F6), - U64(0x5E5637885F29BC2B), U64(0x7EBA726D8C94094B), U64(0x0A56A5F0BFE39272), U64(0xD79476A84EE20D06), - U64(0x9E4C1269BAA4BF37), U64(0x17EFEE45B0DEE640), U64(0x1D95B0A5FCF90BC6), U64(0x93CBE0B699C2585D), - U64(0x65FA4F227A2B6D79), U64(0xD5F9E858292504D5), U64(0xC2B5A03F71471A6F), U64(0x59300222B4561E00), - U64(0xCE2F8642CA0712DC), U64(0x7CA9723FBB2E8988), U64(0x2785338347F2BA08), U64(0xC61BB3A141E50E8C), - U64(0x150F361DAB9DEC26), U64(0x9F6A419D382595F4), U64(0x64A53DC924FE7AC9), U64(0x142DE49FFF7A7C3D), - U64(0x0C335248857FA9E7), U64(0x0A9C32D5EAE45305), U64(0xE6C42178C4BBB92E), U64(0x71F1CE2490D20B07), - U64(0xF1BCC3D275AFE51A), U64(0xE728E8C83C334074), U64(0x96FBF83A12884624), U64(0x81A1549FD6573DA5), - U64(0x5FA7867CAF35E149), U64(0x56986E2EF3ED091B), U64(0x917F1DD5F8886C61), U64(0xD20D8C88C8FFE65F), - U64(0x31D71DCE64B2C310), U64(0xF165B587DF898190), U64(0xA57E6339DD2CF3A0), U64(0x1EF6E6DBB1961EC9), - U64(0x70CC73D90BC26E24), U64(0xE21A6B35DF0C3AD7), U64(0x003A93D8B2806962), U64(0x1C99DED33CB890A1), - U64(0xCF3145DE0ADD4289), U64(0xD0E4427A5514FB72), U64(0x77C621CC9FB3A483), U64(0x67A34DAC4356550B), - U64(0xF8D626AAAF278509), -}; - -// functions - -// random_init() - -void random_init() { - - if ((Random64[RandomNb-1] >> 32) != 0xF8D626AA) { // upper half of the last element of the array - my_fatal("random_init(): broken 64-bit types\n"); - } -} - -// random_64() - -uint64 random_64(int n) { - - ASSERT(n>=0&&n> 32) != 0xF8D626AA) { // upper half of the last element of the array + my_fatal("random_init(): broken 64-bit types\n"); + } +} + +// random_64() + +uint64 random_64(int n) { + + ASSERT(n>=0&&n -#include -#include -#include - -#include "attack.h" -#include "board.h" -#include "list.h" -#include "move.h" -#include "move_gen.h" -#include "move_legal.h" -#include "piece.h" -#include "san.h" -#include "square.h" -#include "util.h" - -// constants - -static const bool UseSlowDebug = FALSE; - -enum ambiguity_t { - AMBIGUITY_NONE, - AMBIGUITY_FILE, - AMBIGUITY_RANK, - AMBIGUITY_SQUARE -}; - -// functions - -static bool san_to_lan (const char san[], const board_t * board, char string[], int size); -static int move_from_lan (const char string[], const board_t * board); - -static int ambiguity (int move, const board_t * board); - -// move_to_san() - -bool move_to_san(int move, const board_t * board, char string[], int size) { - - int from, to, piece; - char tmp_string[256]; - - ASSERT(move_is_ok(move)); - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=8); - - ASSERT(move_is_legal(move,board)); - - if (size < 8) return FALSE; - - // init - - from = move_from(move); - to = move_to(move); - - string[0] = '\0'; - - // castle - - if (move_is_castle(move,board)) { - - if (to > from) { - strcat(string,"O-O"); - } else { - strcat(string,"O-O-O"); - } - - goto check; - } - - // from - - piece = board->square[from]; - - if (piece_is_pawn(piece)) { - - // pawn - - if (move_is_capture(move,board)) { - sprintf(tmp_string,"%c",file_to_char(square_file(from))); - strcat(string,tmp_string); - } - - } else { - - // piece - - sprintf(tmp_string,"%c",toupper(piece_to_char(piece))); - strcat(string,tmp_string); - - // ambiguity - - switch (ambiguity(move,board)) { - case AMBIGUITY_NONE: - break; - case AMBIGUITY_FILE: - sprintf(tmp_string,"%c",file_to_char(square_file(from))); - strcat(string,tmp_string); - break; - case AMBIGUITY_RANK: - sprintf(tmp_string,"%c",rank_to_char(square_rank(from))); - strcat(string,tmp_string); - break; - case AMBIGUITY_SQUARE: - if (!square_to_string(from,tmp_string,256)) return FALSE; - strcat(string,tmp_string); - break; - default: - ASSERT(FALSE); - break; - } - } - - // capture - - if (move_is_capture(move,board)) strcat(string,"x"); - - // to - - if (!square_to_string(to,tmp_string,256)) return FALSE; - strcat(string,tmp_string); - - // promote - - if (move_is_promote(move)) { - sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board)))); - strcat(string,tmp_string); - } - - // check - -check: - - if (move_is_mate(move,board)) { - strcat(string,"#"); - } else if (move_is_check(move,board)) { - strcat(string,"+"); - } - - return TRUE; -} - -// move_from_san() - -int move_from_san(const char string[], const board_t * board) { - - char s[256]; - int move; - - ASSERT(string!=NULL); - ASSERT(board_is_ok(board)); - - san_to_lan(string,board,s,256); - move = move_from_lan(s,board); - - ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board)); - - return move; -} - -// move_from_san_debug() - -int move_from_san_debug(const char string[], const board_t * board) { - - list_t list[1]; - int i, move; - char move_string[256]; - - ASSERT(string!=NULL); - ASSERT(board_is_ok(board)); - - gen_legal_moves(list,board); - - for (i = 0; i < list_size(list); i++) { - move = list_move(list,i); - if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE); - if (my_string_equal(move_string,string)) return move; - } - - return MoveNone; -} - -// san_to_lan() - -static bool san_to_lan(const char san[], const board_t * board, char string[], int size) { - - int len; - int left, right; - int c; - int king, rook; - char king_string[3], rook_string[3]; - - ASSERT(san!=NULL); - ASSERT(board_is_ok(board)); - ASSERT(string!=NULL); - ASSERT(size>=8); - - // init - - if (size < 8) return FALSE; - strcpy(string,"???????"); - - len = strlen(san); - - left = 0; - right = len; - - // skip trailing '+' or '#' - - if (left < right) { - c = san[right-1]; - if (c == '+' || c == '#') right--; - } - - // castling - - ASSERT(left==0); - - if (FALSE) { - - } else if (right == 3 && strncmp(san,"O-O",3) == 0) { - - if (board->castle[board->turn][SideH] == SquareNone) return FALSE; - - king = king_pos(board,board->turn); - rook = board->castle[board->turn][SideH]; - - square_to_string(king,king_string,3); - square_to_string(rook,rook_string,3); - - sprintf(string,"K%s?%s?",king_string,rook_string); - - } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) { - - if (board->castle[board->turn][SideA] == SquareNone) return FALSE; - - king = king_pos(board,board->turn); - rook = board->castle[board->turn][SideA]; - - square_to_string(king,king_string,3); - square_to_string(rook,rook_string,3); - - sprintf(string,"K%s?%s?",king_string,rook_string); - - } else { - - // moved piece - - if (left < right) { - - c = san[left]; - - if (char_is_piece(c)) { - string[0] = c; - left++; - } - } - - // promotion - - if (left < right) { - - c = toupper(san[right-1]); - - if (char_is_piece(c)) { - - string[6] = c; - right--; - - // skip '=' - - if (left < right && san[right-1] == '=') right--; - } - } - - // to-square rank - - if (left < right) { - - c = san[right-1]; - - if (char_is_rank(c)) { - string[5] = c; - right--; - } - } - - // to-square file - - if (left < right) { - - c = san[right-1]; - - if (char_is_file(c)) { - string[4] = c; - right--; - } - } - - // captured piece - - if (left < right) { - - c = san[right-1]; - - if (char_is_piece(c)) { - string[3] = c; - right--; - } - } - - // skip middle '-' or 'x' - - if (left < right) { - c = san[right-1]; - if (c == '-' || c == 'x') right--; - } - - // from-square file - - if (left < right) { - - c = san[left]; - - if (char_is_file(c)) { - string[1] = c; - left++; - } - } - - // from-square rank - - if (left < right) { - - c = san[left]; - - if (char_is_rank(c)) { - string[2] = c; - left++; - } - } - - if (left != right) return FALSE; - } - - // end - - return TRUE; -} - -// move_from_lan() - -static int move_from_lan(const char string[], const board_t * board) { - - int len; - int move; - int promote; - char s[256]; - int from, to; - int colour; - int inc; - int piece_char; - int n; - const uint8 * ptr; - int piece; - int side; - - ASSERT(string!=NULL); - ASSERT(board_is_ok(board)); - - // init - - len = strlen(string); - if (len != 7) return MoveNone; - - move = MoveNone; - colour = board->turn; - - // promote - - promote = 0; - - switch (string[6]) { - case '?': // not a promotion - break; - case 'N': - promote = MovePromoteKnight; - break; - case 'B': - promote = MovePromoteBishop; - break; - case 'R': - promote = MovePromoteRook; - break; - case 'Q': - promote = MovePromoteQueen; - break; - default: - return MoveNone; - break; - } - - // to square - - s[0] = string[4]; - s[1] = string[5]; - s[2] = '\0'; - - to = square_from_string(s); - if (to == SquareNone) return MoveNone; - - // known from square? - - if (string[1] != '?' && string[2] != '?') { - - // from square - - s[0] = string[1]; - s[1] = string[2]; - s[2] = '\0'; - - from = square_from_string(s); - if (from == SquareNone) return MoveNone; - - // convert "king slide" castling to KxR - - if (piece_is_king(board->square[from]) - && square_rank(to) == square_rank(from) - && abs(to-from) > 1) { - side = (to > from) ? SideH : SideA; - to = board->castle[colour][side]; - if (to == SquareNone) return MoveNone; - } - - // move - - move = move_make(from,to) | promote; - - return move; - } - - // pawn non-capture? - - if (string[0] == '?' && string[1] == '?') { - - if (board->square[to] != Empty) return MoveNone; // useful? - - inc = (colour_is_white(colour)) ? +16 : -16; - - from = to - inc; - if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) { - from -= inc; - } - - if (board->square[from] != piece_make_pawn(colour)) { // useful? - return MoveNone; - } - - // move - - move = move_make(from,to) | promote; - - return move; - } - - // pawn capture? - - piece_char = string[0]; - - if (piece_char == '?' && string[1] != '?') { - piece_char = 'P'; - } - - // attack loop - - n = 0; - - for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { - - piece = board->square[from]; - - if (toupper(piece_to_char(piece)) == piece_char) { - if (piece_attack(board,piece,from,to)) { - if (TRUE - && (string[1] == '?' || file_to_char(square_file(from)) == string[1]) - && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) { - if (!is_pinned(board,from,to,colour)) { - move = move_make(from,to) | promote; - n++; - } - } - } - } - } - - if (n != 1) move = MoveNone; - - return move; -} - -// ambiguity() - -static int ambiguity(int move, const board_t * board) { - - int from, to, piece; - list_t list[1]; - int i, n, m; - - // init - - from = move_from(move); - to = move_to(move); - piece = move_piece(move,board); - - gen_legal_moves(list,board); - - // no ambiguity? - - n = 0; - - for (i = 0; i < list_size(list); i++) { - m = list_move(list,i); - if (move_piece(m,board) == piece && move_to(m) == to) { - n++; - } - } - - if (n == 1) return AMBIGUITY_NONE; - - // file ambiguity? - - n = 0; - - for (i = 0; i < list_size(list); i++) { - m = list_move(list,i); - if (move_piece(m,board) == piece && move_to(m) == to) { - if (square_file(move_from(m)) == square_file(from)) n++; - } - } - - if (n == 1) return AMBIGUITY_FILE; - - // rank ambiguity? - - n = 0; - - for (i = 0; i < list_size(list); i++) { - m = list_move(list,i); - if (move_piece(m,board) == piece && move_to(m) == to) { - if (square_rank(move_from(m)) == square_rank(from)) n++; - } - } - - if (n == 1) return AMBIGUITY_RANK; - - // square ambiguity - - return AMBIGUITY_SQUARE; -} - -// end of san.cpp - + +// san.c + +// includes + +#include +#include +#include +#include + +#include "attack.h" +#include "board.h" +#include "list.h" +#include "move.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "san.h" +#include "square.h" +#include "util.h" + +// constants + +static const bool UseSlowDebug = FALSE; + +enum ambiguity_t { + AMBIGUITY_NONE, + AMBIGUITY_FILE, + AMBIGUITY_RANK, + AMBIGUITY_SQUARE +}; + +// functions + +static bool san_to_lan (const char san[], const board_t * board, char string[], int size); +static int move_from_lan (const char string[], const board_t * board); + +static int ambiguity (int move, const board_t * board); + +// move_to_san() + +bool move_to_san(int move, const board_t * board, char string[], int size) { + + int from, to, piece; + char tmp_string[256]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=8); + + ASSERT(move_is_legal(move,board)); + + if (size < 8) return FALSE; + + // init + + from = move_from(move); + to = move_to(move); + + string[0] = '\0'; + + // castle + + if (move_is_castle(move,board)) { + + if (to > from) { + strcat(string,"O-O"); + } else { + strcat(string,"O-O-O"); + } + + goto check; + } + + // from + + piece = board->square[from]; + + if (piece_is_pawn(piece)) { + + // pawn + + if (move_is_capture(move,board)) { + sprintf(tmp_string,"%c",file_to_char(square_file(from))); + strcat(string,tmp_string); + } + + } else { + + // piece + + sprintf(tmp_string,"%c",toupper(piece_to_char(piece))); + strcat(string,tmp_string); + + // ambiguity + + switch (ambiguity(move,board)) { + case AMBIGUITY_NONE: + break; + case AMBIGUITY_FILE: + sprintf(tmp_string,"%c",file_to_char(square_file(from))); + strcat(string,tmp_string); + break; + case AMBIGUITY_RANK: + sprintf(tmp_string,"%c",rank_to_char(square_rank(from))); + strcat(string,tmp_string); + break; + case AMBIGUITY_SQUARE: + if (!square_to_string(from,tmp_string,256)) return FALSE; + strcat(string,tmp_string); + break; + default: + ASSERT(FALSE); + break; + } + } + + // capture + + if (move_is_capture(move,board)) strcat(string,"x"); + + // to + + if (!square_to_string(to,tmp_string,256)) return FALSE; + strcat(string,tmp_string); + + // promote + + if (move_is_promote(move)) { + sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board)))); + strcat(string,tmp_string); + } + + // check + +check: + + if (move_is_mate(move,board)) { + strcat(string,"#"); + } else if (move_is_check(move,board)) { + strcat(string,"+"); + } + + return TRUE; +} + +// move_from_san() + +int move_from_san(const char string[], const board_t * board) { + + char s[256]; + int move; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + san_to_lan(string,board,s,256); + move = move_from_lan(s,board); + + ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board)); + + return move; +} + +// move_from_san_debug() + +int move_from_san_debug(const char string[], const board_t * board) { + + list_t list[1]; + int i, move; + char move_string[256]; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + gen_legal_moves(list,board); + + for (i = 0; i < list_size(list); i++) { + move = list_move(list,i); + if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE); + if (my_string_equal(move_string,string)) return move; + } + + return MoveNone; +} + +// san_to_lan() + +static bool san_to_lan(const char san[], const board_t * board, char string[], int size) { + + int len; + int left, right; + int c; + int king, rook; + char king_string[3], rook_string[3]; + + ASSERT(san!=NULL); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=8); + + // init + + if (size < 8) return FALSE; + strcpy(string,"???????"); + + len = strlen(san); + + left = 0; + right = len; + + // skip trailing '+' or '#' + + if (left < right) { + c = san[right-1]; + if (c == '+' || c == '#') right--; + } + + // castling + + ASSERT(left==0); + + if (FALSE) { + + } else if (right == 3 && strncmp(san,"O-O",3) == 0) { + + if (board->castle[board->turn][SideH] == SquareNone) return FALSE; + + king = king_pos(board,board->turn); + rook = board->castle[board->turn][SideH]; + + square_to_string(king,king_string,3); + square_to_string(rook,rook_string,3); + + sprintf(string,"K%s?%s?",king_string,rook_string); + + } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) { + + if (board->castle[board->turn][SideA] == SquareNone) return FALSE; + + king = king_pos(board,board->turn); + rook = board->castle[board->turn][SideA]; + + square_to_string(king,king_string,3); + square_to_string(rook,rook_string,3); + + sprintf(string,"K%s?%s?",king_string,rook_string); + + } else { + + // moved piece + + if (left < right) { + + c = san[left]; + + if (char_is_piece(c)) { + string[0] = c; + left++; + } + } + + // promotion + + if (left < right) { + + c = toupper(san[right-1]); + + if (char_is_piece(c)) { + + string[6] = c; + right--; + + // skip '=' + + if (left < right && san[right-1] == '=') right--; + } + } + + // to-square rank + + if (left < right) { + + c = san[right-1]; + + if (char_is_rank(c)) { + string[5] = c; + right--; + } + } + + // to-square file + + if (left < right) { + + c = san[right-1]; + + if (char_is_file(c)) { + string[4] = c; + right--; + } + } + + // captured piece + + if (left < right) { + + c = san[right-1]; + + if (char_is_piece(c)) { + string[3] = c; + right--; + } + } + + // skip middle '-' or 'x' + + if (left < right) { + c = san[right-1]; + if (c == '-' || c == 'x') right--; + } + + // from-square file + + if (left < right) { + + c = san[left]; + + if (char_is_file(c)) { + string[1] = c; + left++; + } + } + + // from-square rank + + if (left < right) { + + c = san[left]; + + if (char_is_rank(c)) { + string[2] = c; + left++; + } + } + + if (left != right) return FALSE; + } + + // end + + return TRUE; +} + +// move_from_lan() + +static int move_from_lan(const char string[], const board_t * board) { + + int len; + int move; + int promote; + char s[256]; + int from, to; + int colour; + int inc; + int piece_char; + int n; + const uint8 * ptr; + int piece; + int side; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + // init + + len = strlen(string); + if (len != 7) return MoveNone; + + move = MoveNone; + colour = board->turn; + + // promote + + promote = 0; + + switch (string[6]) { + case '?': // not a promotion + break; + case 'N': + promote = MovePromoteKnight; + break; + case 'B': + promote = MovePromoteBishop; + break; + case 'R': + promote = MovePromoteRook; + break; + case 'Q': + promote = MovePromoteQueen; + break; + default: + return MoveNone; + break; + } + + // to square + + s[0] = string[4]; + s[1] = string[5]; + s[2] = '\0'; + + to = square_from_string(s); + if (to == SquareNone) return MoveNone; + + // known from square? + + if (string[1] != '?' && string[2] != '?') { + + // from square + + s[0] = string[1]; + s[1] = string[2]; + s[2] = '\0'; + + from = square_from_string(s); + if (from == SquareNone) return MoveNone; + + // convert "king slide" castling to KxR + + if (piece_is_king(board->square[from]) + && square_rank(to) == square_rank(from) + && abs(to-from) > 1) { + side = (to > from) ? SideH : SideA; + to = board->castle[colour][side]; + if (to == SquareNone) return MoveNone; + } + + // move + + move = move_make(from,to) | promote; + + return move; + } + + // pawn non-capture? + + if (string[0] == '?' && string[1] == '?') { + + if (board->square[to] != Empty) return MoveNone; // useful? + + inc = (colour_is_white(colour)) ? +16 : -16; + + from = to - inc; + if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) { + from -= inc; + } + + if (board->square[from] != piece_make_pawn(colour)) { // useful? + return MoveNone; + } + + // move + + move = move_make(from,to) | promote; + + return move; + } + + // pawn capture? + + piece_char = string[0]; + + if (piece_char == '?' && string[1] != '?') { + piece_char = 'P'; + } + + // attack loop + + n = 0; + + for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { + + piece = board->square[from]; + + if (toupper(piece_to_char(piece)) == piece_char) { + if (piece_attack(board,piece,from,to)) { + if (TRUE + && (string[1] == '?' || file_to_char(square_file(from)) == string[1]) + && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) { + if (!is_pinned(board,from,to,colour)) { + move = move_make(from,to) | promote; + n++; + } + } + } + } + } + + if (n != 1) move = MoveNone; + + return move; +} + +// ambiguity() + +static int ambiguity(int move, const board_t * board) { + + int from, to, piece; + list_t list[1]; + int i, n, m; + + // init + + from = move_from(move); + to = move_to(move); + piece = move_piece(move,board); + + gen_legal_moves(list,board); + + // no ambiguity? + + n = 0; + + for (i = 0; i < list_size(list); i++) { + m = list_move(list,i); + if (move_piece(m,board) == piece && move_to(m) == to) { + n++; + } + } + + if (n == 1) return AMBIGUITY_NONE; + + // file ambiguity? + + n = 0; + + for (i = 0; i < list_size(list); i++) { + m = list_move(list,i); + if (move_piece(m,board) == piece && move_to(m) == to) { + if (square_file(move_from(m)) == square_file(from)) n++; + } + } + + if (n == 1) return AMBIGUITY_FILE; + + // rank ambiguity? + + n = 0; + + for (i = 0; i < list_size(list); i++) { + m = list_move(list,i); + if (move_piece(m,board) == piece && move_to(m) == to) { + if (square_rank(move_from(m)) == square_rank(from)) n++; + } + } + + if (n == 1) return AMBIGUITY_RANK; + + // square ambiguity + + return AMBIGUITY_SQUARE; +} + +// end of san.cpp + diff --git a/san.h b/san.h index 5966561..8aa74cf 100644 --- a/san.h +++ b/san.h @@ -1,22 +1,22 @@ - -// san.h - -#ifndef SAN_H -#define SAN_H - -// includes - -#include "board.h" -#include "util.h" - -// functions - -extern bool move_to_san (int move, const board_t * board, char string[], int size); -extern int move_from_san (const char string[], const board_t * board); - -extern int move_from_san_debug (const char string[], const board_t * board); - -#endif // !defined SAN_H - -// end of san.h - + +// san.h + +#ifndef SAN_H +#define SAN_H + +// includes + +#include "board.h" +#include "util.h" + +// functions + +extern bool move_to_san (int move, const board_t * board, char string[], int size); +extern int move_from_san (const char string[], const board_t * board); + +extern int move_from_san_debug (const char string[], const board_t * board); + +#endif // !defined SAN_H + +// end of san.h + diff --git a/search.c b/search.c index a67fbbc..075cc81 100644 --- a/search.c +++ b/search.c @@ -1,252 +1,248 @@ -// search.c - -// includes - -#include -#include -#include - -#include "attack.h" -#include "board.h" -#include "colour.h" -#include "engine.h" -#include "fen.h" -#include "line.h" -#include "list.h" -#include "move.h" -#include "move_do.h" -#include "move_gen.h" -#include "move_legal.h" -#include "option.h" -#include "parse.h" -#include "san.h" -#include "search.h" -#include "uci.h" -#include "util.h" - -// constants - -#define StringSize ((int)4096) - -// variables - -static int Depth; - -static int BestMove; -static int BestValue; -static move_t BestPV[LineSize]; - -static sint64 NodeNb; -static sint64 LeafNb; -static double Time; - -static int Move; -static int MovePos; -static int MoveNb; - -// prototypes - -static bool depth_is_ok (int depth); -static void perft (const board_t * board, int depth); - -// functions - -// depth_is_ok() - -static bool depth_is_ok(int depth) { - - return depth >= 0 && depth < DepthMax; -} - -// search() - -void search(const board_t * board, int depth_max, double time_max) { - - char string[256]; - - ASSERT(board_is_ok(board)); - ASSERT(depth_max>=1&&depth_max=0.0); - - // engine - - Depth = 0; - - BestMove = MoveNone; - BestValue = 0; - line_clear(BestPV); - - NodeNb = 0; - LeafNb = 0; - Time = 0.0; - - Move = MoveNone; - MovePos = 0; - MoveNb = 0; - - // init - - uci_send_ucinewgame(Uci); - uci_send_isready_sync(Uci); - - // position - - if (!board_to_fen(board,string,256)) ASSERT(FALSE); - engine_send(Engine,"position fen %s",string); - - // search - - engine_send_queue(Engine,"go"); - - engine_send_queue(Engine," movetime %.0f",time_max*1000.0); - engine_send_queue(Engine," depth %d",depth_max); - - engine_send(Engine,""); // newline - - // wait for feed-back - - while (!engine_eof(Engine)) { - - engine_get(Engine,string); - - if (FALSE) { - - } else if (match(string,"bestmove * ponder *")) { - - BestMove = move_from_can(Star[0],board); - ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); - - break; - - } else if (match(string,"bestmove *")) { - - BestMove = move_from_can(Star[0],board); - ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); - - break; - } - } - - printf("\n"); -} - -// do_perft() - -void do_perft(int argc,char * argv[]){ - const char * fen=NULL; - int depth=1; - board_t board[1]; - int i; - for (i = 1; i < argc; i++) { - if (FALSE) { - } else if (my_string_equal(argv[i],"perft")) { - // skip - } else if (my_string_equal(argv[i],"-fen")) { - i++; - if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); - my_string_set(&fen,argv[i]); - } else if (my_string_equal(argv[i],"-max-depth")){ - i++; - if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); - depth=atoi(argv[i]); - if(depth<1) my_fatal("do_perft(): illegal depth %d\n",depth); - } else { - my_fatal("do_perft(): unknown option \"%s\"\n",argv[i]); - } - } - if(fen==NULL){ - my_string_set(&fen,StartFen); - } - board_from_fen(board,fen); - search_perft(board,depth); -} - -// search_perft() - -void search_perft(const board_t * board, int depth_max) { - - int depth; - my_timer_t timer[1]; - double time, speed; - char node_string[StringSize]; - char leafnode_string[StringSize]; - - ASSERT(board_is_ok(board)); - ASSERT(depth_max>=1&&depth_maxturn))); - - // init - - NodeNb++; - - // leaf - - if (depth == 0) { - LeafNb++; - return; - } - - // more init - - me = board->turn; - - // move loop - - gen_moves(list,board); - - for (i = 0; i < list_size(list); i++) { - - move = list_move(list,i); - - board_copy(new_board,board); - move_do(new_board,move); - - if (!is_in_check(new_board,me)) perft(new_board,depth-1); - } -} - -// end of search.cpp - +// search.c + +// includes + +#include +#include +#include + +#include "attack.h" +#include "board.h" +#include "colour.h" +#include "engine.h" +#include "fen.h" +#include "line.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "search.h" +#include "uci.h" +#include "util.h" + +// variables + +static int Depth; + +static int BestMove; +static int BestValue; +static move_t BestPV[LineSize]; + +static sint64 NodeNb; +static sint64 LeafNb; +static double Time; + +static int Move; +static int MovePos; +static int MoveNb; + +// prototypes + +static bool depth_is_ok (int depth); +static void perft (const board_t * board, int depth); + +// functions + +// depth_is_ok() + +static bool depth_is_ok(int depth) { + + return depth >= 0 && depth < DepthMax; +} + +// search() + +void search(const board_t * board, int depth_max, double time_max) { + + char string[256]; + + ASSERT(board_is_ok(board)); + ASSERT(depth_max>=1&&depth_max=0.0); + + // engine + + Depth = 0; + + BestMove = MoveNone; + BestValue = 0; + line_clear(BestPV); + + NodeNb = 0; + LeafNb = 0; + Time = 0.0; + + Move = MoveNone; + MovePos = 0; + MoveNb = 0; + + // init + + uci_send_ucinewgame(Uci); + uci_send_isready_sync(Uci); + + // position + + if (!board_to_fen(board,string,256)) ASSERT(FALSE); + engine_send(Engine,"position fen %s",string); + + // search + + engine_send_queue(Engine,"go"); + + engine_send_queue(Engine," movetime %.0f",time_max*1000.0); + engine_send_queue(Engine," depth %d",depth_max); + + engine_send(Engine,""); // newline + + // wait for feed-back + + while (!engine_eof(Engine)) { + + engine_get(Engine,string); + + if (FALSE) { + + } else if (match(string,"bestmove * ponder *")) { + + BestMove = move_from_can(Star[0],board); + ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); + + break; + + } else if (match(string,"bestmove *")) { + + BestMove = move_from_can(Star[0],board); + ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); + + break; + } + } + + printf("\n"); +} + +// do_perft() + +void do_perft(int argc,char * argv[]){ + const char * fen=NULL; + int depth=1; + board_t board[1]; + int i; + for (i = 1; i < argc; i++) { + if (FALSE) { + } else if (my_string_equal(argv[i],"perft")) { + // skip + } else if (my_string_equal(argv[i],"-fen")) { + i++; + if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); + my_string_set(&fen,argv[i]); + } else if (my_string_equal(argv[i],"-max-depth")){ + i++; + if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); + depth=atoi(argv[i]); + if(depth<1) my_fatal("do_perft(): illegal depth %d\n",depth); + } else { + my_fatal("do_perft(): unknown option \"%s\"\n",argv[i]); + } + } + if(fen==NULL){ + my_string_set(&fen,StartFen); + } + board_from_fen(board,fen); + search_perft(board,depth); +} + +// search_perft() + +void search_perft(const board_t * board, int depth_max) { + + int depth; + my_timer_t timer[1]; + double time, speed; + char node_string[StringSize]; + char leafnode_string[StringSize]; + + ASSERT(board_is_ok(board)); + ASSERT(depth_max>=1&&depth_maxturn))); + + // init + + NodeNb++; + + // leaf + + if (depth == 0) { + LeafNb++; + return; + } + + // more init + + me = board->turn; + + // move loop + + gen_moves(list,board); + + for (i = 0; i < list_size(list); i++) { + + move = list_move(list,i); + + board_copy(new_board,board); + move_do(new_board,move); + + if (!is_in_check(new_board,me)) perft(new_board,depth-1); + } +} + +// end of search.cpp + diff --git a/search.h b/search.h index b537297..1206ea8 100644 --- a/search.h +++ b/search.h @@ -1,25 +1,25 @@ -// search.h - -#ifndef SEARCH_H -#define SEARCH_H - -// includes - -#include "board.h" -#include "util.h" - -// defines - -#define DepthMax 63 - -// functions - -extern void search (const board_t * board, int depth_max, double time_max); -extern void search_perft (const board_t * board, int depth_max); - -extern void do_perft (int argc, char * argv[]); - -#endif // !defined SEARCH_H - -// end of search.h - +// search.h + +#ifndef SEARCH_H +#define SEARCH_H + +// includes + +#include "board.h" +#include "util.h" + +// defines + +#define DepthMax 63 + +// functions + +extern void search (const board_t * board, int depth_max, double time_max); +extern void search_perft (const board_t * board, int depth_max); + +extern void do_perft (int argc, char * argv[]); + +#endif // !defined SEARCH_H + +// end of search.h + diff --git a/square.c b/square.c index f5a0fe9..f4e3afb 100644 --- a/square.c +++ b/square.c @@ -1,246 +1,246 @@ - -// square.c - -// includes - -#include "colour.h" -#include "square.h" -#include "util.h" - -// "constants" - -static const uint8 SquareFrom64[64] = { - A1, B1, C1, D1, E1, F1, G1, H1, - A2, B2, C2, D2, E2, F2, G2, H2, - A3, B3, C3, D3, E3, F3, G3, H3, - A4, B4, C4, D4, E4, F4, G4, H4, - A5, B5, C5, D5, E5, F5, G5, H5, - A6, B6, C6, D6, E6, F6, G6, H6, - A7, B7, C7, D7, E7, F7, G7, H7, - A8, B8, C8, D8, E8, F8, G8, H8, -}; - -// variables - -static sint8 SquareTo64[SquareNb]; - -// functions - -// square_init() - -void square_init() { - - int sq; - - for (sq = 0; sq < SquareNb; sq++) SquareTo64[sq] = -1; - - for (sq = 0; sq < 64; sq++) { - SquareTo64[SquareFrom64[sq]] = sq; - } -} - -// square_is_ok() - -bool square_is_ok(int square) { - - if (square < 0 || square >= SquareNb) return FALSE; - - if (SquareTo64[square] < 0) return FALSE; - - return TRUE; -} - -// square_make() - -int square_make(int file, int rank) { - - int sq_64; - - ASSERT(file>=0&&file<8); - ASSERT(rank>=0&&rank<8); - - sq_64 = (rank << 3) | file; - - return square_from_64(sq_64); -} - -// square_file() - -int square_file(int square) { - - int file; - - ASSERT(square_is_ok(square)); - - file = (square - 4) & 7; - ASSERT(file==(square_to_64(square)&7)); - - return file; -} - -// square_rank() - -int square_rank(int square) { - - int rank; - - ASSERT(square_is_ok(square)); - - rank = (square >> 4) - 2; - ASSERT(rank==square_to_64(square)>>3); - - return rank; -} - -// square_side_rank() - -int square_side_rank(int square, int colour) { - - int rank; - - ASSERT(square_is_ok(square)); - ASSERT(colour_is_ok(colour)); - - rank = square_rank(square); - if (colour_is_black(colour)) rank = 7-rank; - - return rank; -} - -// square_from_64() - -int square_from_64(int square) { - - ASSERT(square>=0&&square<64); - - return SquareFrom64[square]; -} - -// square_to_64() - -int square_to_64(int square) { - - ASSERT(square_is_ok(square)); - - return SquareTo64[square]; -} - -// square_is_promote() - -bool square_is_promote(int square) { - - int rank; - - ASSERT(square_is_ok(square)); - - rank = square_rank(square); - - return rank == Rank1 || rank == Rank8; -} - -// square_ep_dual() - -int square_ep_dual(int square) { - - ASSERT(square_is_ok(square)); - ASSERT(square_rank(square)>=2&&square_rank(square)<=5); - - return square ^ 16; -} - -// square_colour() - -int square_colour(int square) { - - ASSERT(square_is_ok(square)); - - return (square ^ (square >> 4)) & 1; -} - -// file_from_char() - -int file_from_char(int c) { - - ASSERT(c>='a'&&c<='h'); - - return c - 'a'; -} - -// rank_from_char() - -int rank_from_char(int c) { - - ASSERT(c>='1'&&c<='8'); - - return c - '1'; -} - -// file_to_char() - -int file_to_char(int file) { - - ASSERT(file>=0&&file<8); - - return 'a' + file; -} - -// rank_to_char() - -int rank_to_char(int rank) { - - ASSERT(rank>=0&&rank<8); - - return '1' + rank; -} - -// char_is_file() - -bool char_is_file(int c) { - - return c >= 'a' && c <= 'h'; -} - -// char_is_rank() - -bool char_is_rank(int c) { - - return c >= '1' && c <= '8'; -} - -// square_to_string() - -bool square_to_string(int square, char string[], int size) { - - ASSERT(square_is_ok(square)); - ASSERT(string!=NULL); - ASSERT(size>=3); - - if (size < 3) return FALSE; - - string[0] = 'a' + square_file(square); - string[1] = '1' + square_rank(square); - string[2] = '\0'; - - return TRUE; -} - -// square_from_string() - -int square_from_string(const char string[]) { - - int file, rank; - - ASSERT(string!=NULL); - - if (string[0] < 'a' || string[0] > 'h') return SquareNone; - if (string[1] < '1' || string[1] > '8') return SquareNone; - if (string[2] != '\0') return SquareNone; - - file = file_from_char(string[0]); - rank = rank_from_char(string[1]); - - return square_make(file,rank); -} - -// end of square.cpp - + +// square.c + +// includes + +#include "colour.h" +#include "square.h" +#include "util.h" + +// "constants" + +static const uint8 SquareFrom64[64] = { + A1, B1, C1, D1, E1, F1, G1, H1, + A2, B2, C2, D2, E2, F2, G2, H2, + A3, B3, C3, D3, E3, F3, G3, H3, + A4, B4, C4, D4, E4, F4, G4, H4, + A5, B5, C5, D5, E5, F5, G5, H5, + A6, B6, C6, D6, E6, F6, G6, H6, + A7, B7, C7, D7, E7, F7, G7, H7, + A8, B8, C8, D8, E8, F8, G8, H8, +}; + +// variables + +static sint8 SquareTo64[SquareNb]; + +// functions + +// square_init() + +void square_init() { + + int sq; + + for (sq = 0; sq < SquareNb; sq++) SquareTo64[sq] = -1; + + for (sq = 0; sq < 64; sq++) { + SquareTo64[SquareFrom64[sq]] = sq; + } +} + +// square_is_ok() + +bool square_is_ok(int square) { + + if (square < 0 || square >= SquareNb) return FALSE; + + if (SquareTo64[square] < 0) return FALSE; + + return TRUE; +} + +// square_make() + +int square_make(int file, int rank) { + + int sq_64; + + ASSERT(file>=0&&file<8); + ASSERT(rank>=0&&rank<8); + + sq_64 = (rank << 3) | file; + + return square_from_64(sq_64); +} + +// square_file() + +int square_file(int square) { + + int file; + + ASSERT(square_is_ok(square)); + + file = (square - 4) & 7; + ASSERT(file==(square_to_64(square)&7)); + + return file; +} + +// square_rank() + +int square_rank(int square) { + + int rank; + + ASSERT(square_is_ok(square)); + + rank = (square >> 4) - 2; + ASSERT(rank==square_to_64(square)>>3); + + return rank; +} + +// square_side_rank() + +int square_side_rank(int square, int colour) { + + int rank; + + ASSERT(square_is_ok(square)); + ASSERT(colour_is_ok(colour)); + + rank = square_rank(square); + if (colour_is_black(colour)) rank = 7-rank; + + return rank; +} + +// square_from_64() + +int square_from_64(int square) { + + ASSERT(square>=0&&square<64); + + return SquareFrom64[square]; +} + +// square_to_64() + +int square_to_64(int square) { + + ASSERT(square_is_ok(square)); + + return SquareTo64[square]; +} + +// square_is_promote() + +bool square_is_promote(int square) { + + int rank; + + ASSERT(square_is_ok(square)); + + rank = square_rank(square); + + return rank == Rank1 || rank == Rank8; +} + +// square_ep_dual() + +int square_ep_dual(int square) { + + ASSERT(square_is_ok(square)); + ASSERT(square_rank(square)>=2&&square_rank(square)<=5); + + return square ^ 16; +} + +// square_colour() + +int square_colour(int square) { + + ASSERT(square_is_ok(square)); + + return (square ^ (square >> 4)) & 1; +} + +// file_from_char() + +int file_from_char(int c) { + + ASSERT(c>='a'&&c<='h'); + + return c - 'a'; +} + +// rank_from_char() + +int rank_from_char(int c) { + + ASSERT(c>='1'&&c<='8'); + + return c - '1'; +} + +// file_to_char() + +int file_to_char(int file) { + + ASSERT(file>=0&&file<8); + + return 'a' + file; +} + +// rank_to_char() + +int rank_to_char(int rank) { + + ASSERT(rank>=0&&rank<8); + + return '1' + rank; +} + +// char_is_file() + +bool char_is_file(int c) { + + return c >= 'a' && c <= 'h'; +} + +// char_is_rank() + +bool char_is_rank(int c) { + + return c >= '1' && c <= '8'; +} + +// square_to_string() + +bool square_to_string(int square, char string[], int size) { + + ASSERT(square_is_ok(square)); + ASSERT(string!=NULL); + ASSERT(size>=3); + + if (size < 3) return FALSE; + + string[0] = 'a' + square_file(square); + string[1] = '1' + square_rank(square); + string[2] = '\0'; + + return TRUE; +} + +// square_from_string() + +int square_from_string(const char string[]) { + + int file, rank; + + ASSERT(string!=NULL); + + if (string[0] < 'a' || string[0] > 'h') return SquareNone; + if (string[1] < '1' || string[1] > '8') return SquareNone; + if (string[2] != '\0') return SquareNone; + + file = file_from_char(string[0]); + rank = rank_from_char(string[1]); + + return square_make(file,rank); +} + +// end of square.cpp + diff --git a/square.h b/square.h index b493597..0cf9d39 100644 --- a/square.h +++ b/square.h @@ -1,138 +1,138 @@ - -// square.h - -#ifndef SQUARE_H -#define SQUARE_H - -// includes - -#include "util.h" - -// defines - -#define SquareNb (16 * 12) - -#define FileA 0 -#define FileB 1 -#define FileC 2 -#define FileD 3 -#define FileE 4 -#define FileF 5 -#define FileG 6 -#define FileH 7 - -#define Rank1 0 -#define Rank2 1 -#define Rank3 2 -#define Rank4 3 -#define Rank5 4 -#define Rank6 5 -#define Rank7 6 -#define Rank8 7 - -#define SquareNone 0 - -#define A1 0x24 -#define B1 0x25 -#define C1 0x26 -#define D1 0x27 -#define E1 0x28 -#define F1 0x29 -#define G1 0x2A -#define H1 0x2B -#define A2 0x34 -#define B2 0x35 -#define C2 0x36 -#define D2 0x37 -#define E2 0x38 -#define F2 0x39 -#define G2 0x3A -#define H2 0x3B -#define A3 0x44 -#define B3 0x45 -#define C3 0x46 -#define D3 0x47 -#define E3 0x48 -#define F3 0x49 -#define G3 0x4A -#define H3 0x4B -#define A4 0x54 -#define B4 0x55 -#define C4 0x56 -#define D4 0x57 -#define E4 0x58 -#define F4 0x59 -#define G4 0x5A -#define H4 0x5B -#define A5 0x64 -#define B5 0x65 -#define C5 0x66 -#define D5 0x67 -#define E5 0x68 -#define F5 0x69 -#define G5 0x6A -#define H5 0x6B -#define A6 0x74 -#define B6 0x75 -#define C6 0x76 -#define D6 0x77 -#define E6 0x78 -#define F6 0x79 -#define G6 0x7A -#define H6 0x7B -#define A7 0x84 -#define B7 0x85 -#define C7 0x86 -#define D7 0x87 -#define E7 0x88 -#define F7 0x89 -#define G7 0x8A -#define H7 0x8B -#define A8 0x94 -#define B8 0x95 -#define C8 0x96 -#define D8 0x97 -#define E8 0x98 -#define F8 0x99 -#define G8 0x9A -#define H8 0x9B - -#define Dark 0 -#define Light 1 - -// functions - -extern void square_init (); - -extern bool square_is_ok (int square); - -extern int square_make (int file, int rank); - -extern int square_file (int square); -extern int square_rank (int square); -extern int square_side_rank (int square, int colour); - -extern int square_from_64 (int square); -extern int square_to_64 (int square); - -extern bool square_is_promote (int square); -extern int square_ep_dual (int square); - -extern int square_colour (int square); - -extern bool char_is_file (int c); -extern bool char_is_rank (int c); - -extern int file_from_char (int c); -extern int rank_from_char (int c); - -extern int file_to_char (int file); -extern int rank_to_char (int rank); - -extern bool square_to_string (int square, char string[], int size); -extern int square_from_string (const char string[]); - -#endif // !defined SQUARE_H - -// end of square.h - + +// square.h + +#ifndef SQUARE_H +#define SQUARE_H + +// includes + +#include "util.h" + +// defines + +#define SquareNb (16 * 12) + +#define FileA 0 +#define FileB 1 +#define FileC 2 +#define FileD 3 +#define FileE 4 +#define FileF 5 +#define FileG 6 +#define FileH 7 + +#define Rank1 0 +#define Rank2 1 +#define Rank3 2 +#define Rank4 3 +#define Rank5 4 +#define Rank6 5 +#define Rank7 6 +#define Rank8 7 + +#define SquareNone 0 + +#define A1 0x24 +#define B1 0x25 +#define C1 0x26 +#define D1 0x27 +#define E1 0x28 +#define F1 0x29 +#define G1 0x2A +#define H1 0x2B +#define A2 0x34 +#define B2 0x35 +#define C2 0x36 +#define D2 0x37 +#define E2 0x38 +#define F2 0x39 +#define G2 0x3A +#define H2 0x3B +#define A3 0x44 +#define B3 0x45 +#define C3 0x46 +#define D3 0x47 +#define E3 0x48 +#define F3 0x49 +#define G3 0x4A +#define H3 0x4B +#define A4 0x54 +#define B4 0x55 +#define C4 0x56 +#define D4 0x57 +#define E4 0x58 +#define F4 0x59 +#define G4 0x5A +#define H4 0x5B +#define A5 0x64 +#define B5 0x65 +#define C5 0x66 +#define D5 0x67 +#define E5 0x68 +#define F5 0x69 +#define G5 0x6A +#define H5 0x6B +#define A6 0x74 +#define B6 0x75 +#define C6 0x76 +#define D6 0x77 +#define E6 0x78 +#define F6 0x79 +#define G6 0x7A +#define H6 0x7B +#define A7 0x84 +#define B7 0x85 +#define C7 0x86 +#define D7 0x87 +#define E7 0x88 +#define F7 0x89 +#define G7 0x8A +#define H7 0x8B +#define A8 0x94 +#define B8 0x95 +#define C8 0x96 +#define D8 0x97 +#define E8 0x98 +#define F8 0x99 +#define G8 0x9A +#define H8 0x9B + +#define Dark 0 +#define Light 1 + +// functions + +extern void square_init (); + +extern bool square_is_ok (int square); + +extern int square_make (int file, int rank); + +extern int square_file (int square); +extern int square_rank (int square); +extern int square_side_rank (int square, int colour); + +extern int square_from_64 (int square); +extern int square_to_64 (int square); + +extern bool square_is_promote (int square); +extern int square_ep_dual (int square); + +extern int square_colour (int square); + +extern bool char_is_file (int c); +extern bool char_is_rank (int c); + +extern int file_from_char (int c); +extern int rank_from_char (int c); + +extern int file_to_char (int file); +extern int rank_to_char (int rank); + +extern bool square_to_string (int square, char string[], int size); +extern int square_from_string (const char string[]); + +#endif // !defined SQUARE_H + +// end of square.h + diff --git a/uci.c b/uci.c index 05d60b3..42b5971 100644 --- a/uci.c +++ b/uci.c @@ -1,963 +1,961 @@ - -// uci.c - -// includes - -#include -#include -#include -#include - -#include "board.h" -#include "engine.h" -#include "gui.h" -#include "move.h" -#include "move_do.h" -#include "move_legal.h" -#include "option.h" -#include "parse.h" -#include "line.h" -#include "uci.h" - - -// constants - -static const bool UseDebug = FALSE; - -#define StringSize ((int)4096) - -// variables - -uci_t Uci[1]; - -// Hopefully the following confusion is temporary -// Normally we should check for the engine name but this is a hack anyway -// Some of there where provided by Marc Lacrosse - -const char * thread_options[]={ - "number of threads", // toga - "number threads", // Deep Learning Toga - "threads", // glaurung, zappa, cyclone, grapefruit, - // Deep Shredder, Deep Junior, bright - "core threads", // HIARCS - "max cpus", // rybka - "cpus", // Deep Sjeng, Fruit2.3.5 - "maxthreads", // Naum - NULL -}; - -// prototypes - -static bool uci_is_ok (const uci_t * uci); - -static int parse_bestmove (uci_t * uci, const char string[]); -static void parse_id (uci_t * uci, const char string[]); -static int parse_info (uci_t * uci, const char string[]); -static void parse_option (uci_t * uci, const char string[]); -static void parse_score (uci_t * uci, const char string[]); - -static int mate_score (int dist); - -// functions - - -// uci_adapt_UCI3() - -static void apply_UCI3_heuristics(option_t *opt){ - if(option_get_int(Option,"UCIVersion")>2){ - return; - } - if(!my_string_equal(opt->type,"string")){ - return; - } - if(!strncmp(opt->name,"UCI_",4)){ - return; - } - if(my_string_case_contains(opt->name,"file")){ - my_string_set(&opt->type,"file"); - return; - } - if(my_string_case_contains(opt->name,"path")){ - my_string_set(&opt->type,"path"); - return; - } -} - -// uci_set_threads() - -void uci_set_threads(uci_t * uci, int n) { - const char *thread_option=uci_thread_option(uci); - ASSERT(n>=1); - if(thread_option){ - uci_send_option(uci,thread_option,"%d",n); - } -} - - -const char * uci_thread_option(uci_t * uci){ - const char **p = thread_options; - const char *thread_option; - option_t *opt; - while((thread_option = *(p++))){ - if((opt=option_find(uci->option,thread_option))){ - return opt->name; - break; - } - } - return NULL; -} - -// uci_is_ok() - -static bool uci_is_ok(const uci_t * uci) { - - if (uci == NULL) return FALSE; - if (uci->engine == NULL) return FALSE; - if (!option_is_ok(uci->option)) return FALSE; - return TRUE; -} - -// uci_open() - -void uci_open(uci_t * uci, engine_t * engine) { - - char string[StringSize]; - int event; - - ASSERT(uci!=NULL); - ASSERT(engine!=NULL); - - // init - - uci->engine = engine; - - uci->name = NULL; - my_string_set(&uci->name,""); - uci->author = NULL; - my_string_set(&uci->author,""); - option_init(uci->option); - - uci->ready_nb = 0; - uci->searching = 0; - uci->pending_nb = 0; - uci->multipv_mode = FALSE; - board_start(uci->board); - uci_clear(uci); - - // send "uci" and wait for "uciok" - - engine_send(uci->engine,"uci"); - - do { - engine_get(uci->engine,string); - // Handle the case that the engine is really a WB engine somewhat gracefully. - if((strstr(string,"Illegal") || strstr(string,"Error")) - &&strstr(string,"uci")){ - my_fatal("uci_open(): Not a UCI engine.\n"); - } - event = uci_parse(uci,string); - } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0); -} - -// uci_close() - -void uci_close(uci_t * uci) { - - ASSERT(uci_is_ok(uci)); - engine_close(uci->engine); - uci->engine = NULL; - my_string_clear(&uci->name); - my_string_clear(&uci->author); - - option_clear(uci->option); -} - -// uci_clear() - -void uci_clear(uci_t * uci) { - - ASSERT(uci_is_ok(uci)); - - ASSERT(!uci->searching); - - uci->best_move = MoveNone; - uci->ponder_move = MoveNone; - - uci->score = 0; - uci->depth = 0; - uci->sel_depth = 0; - line_clear(uci->pv); - - uci->best_score = 0; - uci->best_depth = 0; - uci->best_sel_depth = 0; - line_clear(uci->best_pv); -// make the default 1 instead of 0 so that info lines can be recognized by their node number 0 - uci->node_nb = 1; - uci->time = 0.0; - uci->speed = 0.0; - uci->cpu = 0.0; - uci->hash = 0.0; - line_clear(uci->current_line); - - uci->root_move = MoveNone; - uci->root_move_pos = 0; - uci->root_move_nb = board_mobility(uci->board); - - uci->multipvSP=0; -} - -// uci_send_isready() - -void uci_send_isready(uci_t * uci) { - - ASSERT(uci!=NULL); - - engine_send(uci->engine,"isready"); - uci->ready_nb++; -} - -// uci_send_isready_sync() - -void uci_send_isready_sync(uci_t * uci) { - - char string[StringSize]; - int event; - - ASSERT(uci_is_ok(uci)); - - // send "isready" and wait for "readyok" - - uci_send_isready(uci); - - do { - engine_get(uci->engine,string); - event = uci_parse(uci,string); - } while (!engine_eof(Engine) && (event & EVENT_READY) == 0); -} - -// uci_send_stop() - -void uci_send_stop(uci_t * uci) { - - ASSERT(uci_is_ok(uci)); - - ASSERT(uci->searching); - ASSERT(uci->pending_nb>=1); - - engine_send(Engine,"stop"); - uci->searching = FALSE; -} - -// uci_send_stop_sync() - -void uci_send_stop_sync(uci_t * uci) { - - char string[StringSize]; - int event; - - ASSERT(uci_is_ok(uci)); - - ASSERT(uci->searching); - ASSERT(uci->pending_nb>=1); - - // send "stop" and wait for "bestmove" - - uci_send_stop(uci); - - do { - engine_get(uci->engine,string); - event = uci_parse(uci,string); - } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0); -} - -// uci_send_ucinewgame() - -void uci_send_ucinewgame(uci_t * uci) { - - ASSERT(uci!=NULL); - - if (option_get_int(Option,"UCIVersion") >= 2) { - engine_send(uci->engine,"ucinewgame"); - } -} - -// uci_send_option() - -bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) { - - char value[FormatBufferSize]; - option_t * opt; - bool found=FALSE; - - ASSERT(uci_is_ok(uci)); - ASSERT(option!=NULL); - ASSERT(format!=NULL); - - // format - - CONSTRUCT_ARG_STRING(format,value); - - if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value); - - opt=option_find(uci->option,option); - if(opt){ - found=TRUE; - if(!IS_BUTTON(opt->type)){ - if(!my_string_equal(opt->value,value)){ - engine_send(uci->engine,"setoption name %s value %s", - opt->name,value); - my_string_set(&opt->value,value); - }else{ - my_log("POLYGLOT Not sending option \"%s\" since it " - "already has the correct value.\n",opt->name); - } - }else{ - engine_send(uci->engine,"setoption name %s",opt->name); - } - } - return found; -} - -// uci_parse() - -int uci_parse(uci_t * uci, const char string[]) { - - int event; - parse_t parse[1]; - char command[StringSize]; - char argument[StringSize]; - - ASSERT(uci_is_ok(uci)); - ASSERT(string!=NULL); - - // init - - event = EVENT_NONE; - - // parse - - parse_open(parse,string); - - if (parse_get_word(parse,command,StringSize)) { - - parse_get_string(parse,argument,StringSize); - if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument); - - if (FALSE) { - - } else if (my_string_equal(command,"bestmove")) { - - // search end - - ASSERT(uci->pending_nb>0); - - if (uci->searching && uci->pending_nb == 1) { - - // current search - - uci->searching = FALSE; - uci->pending_nb--; - - event = parse_bestmove(uci,argument); // updates uci->best_move and uci->ponder_move - - } else { - - // obsolete search - - if (uci->pending_nb > 0) { - uci->pending_nb--; - if (uci->pending_nb == 0) event = EVENT_STOP; - } - } - - } else if (my_string_equal(command,"id")) { - - parse_id(uci,argument); - - } else if (my_string_equal(command,"info")) { - - // search information - - if (uci->searching && uci->pending_nb == 1) { // current search - event = parse_info(uci,argument); - } - - } else if (my_string_equal(command,"option")) { - - parse_option(uci,argument); - - } else if (my_string_equal(command,"readyok")) { - - // engine is ready - - ASSERT(uci->ready_nb>0); - - if (uci->ready_nb > 0) { - uci->ready_nb--; - if (uci->ready_nb == 0) event = EVENT_READY; - } - - } else if (my_string_equal(command,"uciok")) { - - event = EVENT_UCI; - - } else { - - if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command); - } - } - - parse_close(parse); - - return event; -} - -// parse_bestmove() - -static int parse_bestmove(uci_t * uci, const char string[]) { - - parse_t parse[1]; - char command[StringSize]; - char option[StringSize]; - char argument[StringSize]; - board_t board[1]; - - ASSERT(uci_is_ok(uci)); - ASSERT(string!=NULL); - - // init - - strcpy(command,"bestmove"); - - parse_open(parse,string); - parse_add_keyword(parse,"ponder"); - - // bestmove - - uci->bestmove[0]='\0'; - if (!parse_get_string(parse,argument,StringSize)) { - strcpy(uci->bestmove,"nomove"); - return EVENT_ILLEGAL_MOVE; -// my_fatal("parse_bestmove(): missing argument\n"); - } - strncpy(uci->bestmove,argument,UciStringSize); - uci->bestmove[UciStringSize-1]='\0'; - - uci->best_move = move_from_can(argument,uci->board); - if (uci->best_move == MoveNone) { - return EVENT_ILLEGAL_MOVE; -// my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); - } - - if(!move_is_legal(uci->best_move,uci->board)){ - return EVENT_ILLEGAL_MOVE; - } - ASSERT(uci->best_move!=MoveNone); - ASSERT(move_is_legal(uci->best_move,uci->board)); - - // loop - - while (parse_get_word(parse,option,StringSize)) { - - parse_get_string(parse,argument,StringSize); - - if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); - - if (FALSE) { - - } else if (my_string_equal(option,"ponder")) { - - ASSERT(!my_string_empty(argument)); - - board_copy(board,uci->board); - move_do(board,uci->best_move); - - uci->ponder_move = move_from_can(argument,board); - // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); - - ASSERT(uci->ponder_move!=MoveNone); - ASSERT(move_is_legal(uci->ponder_move,board)); - - } else { - - my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); - } - } - - parse_close(parse); - - return EVENT_MOVE; -} - -// parse_id() - -static void parse_id(uci_t * uci, const char string[]) { - - parse_t parse[1]; - char command[StringSize]; - char option[StringSize]; - char argument[StringSize]; - - ASSERT(uci!=NULL); - ASSERT(string!=NULL); - - // init - - strcpy(command,"id"); - - parse_open(parse,string); - parse_add_keyword(parse,"author"); - parse_add_keyword(parse,"name"); - - // loop - - while (parse_get_word(parse,option,StringSize)) { - - parse_get_string(parse,argument,StringSize); - if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); - - if (FALSE) { - } else if (my_string_equal(option,"author")) { - ASSERT(!my_string_empty(argument)); - my_string_set(&uci->author,argument); - } else if (my_string_equal(option,"name")) { - ASSERT(!my_string_empty(argument)); - my_string_set(&uci->name,argument); - } else { - my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); - } - } - - parse_close(parse); - - if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author); -} - -// parse_info() - -static int parse_info(uci_t * uci, const char string[]) { - - int event; - parse_t parse[1]; - char command[StringSize]; - char option[StringSize]; - char argument[StringSize]; - int n; - int multipvline=0; - sint64 ln; - - - - ASSERT(uci_is_ok(uci)); - ASSERT(string!=NULL); - - // init - - event = EVENT_NONE; - - strcpy(command,"info"); - - parse_open(parse,string); - parse_add_keyword(parse,"cpuload"); - parse_add_keyword(parse,"currline"); - parse_add_keyword(parse,"currmove"); - parse_add_keyword(parse,"currmovenumber"); - parse_add_keyword(parse,"depth"); - parse_add_keyword(parse,"hashfull"); - parse_add_keyword(parse,"multipv"); - parse_add_keyword(parse,"nodes"); - parse_add_keyword(parse,"nps"); - parse_add_keyword(parse,"pv"); - parse_add_keyword(parse,"refutation"); - parse_add_keyword(parse,"score"); - parse_add_keyword(parse,"seldepth"); - parse_add_keyword(parse,"string"); - parse_add_keyword(parse,"tbhits"); - parse_add_keyword(parse,"time"); - - // loop - - while (parse_get_word(parse,option,StringSize)) { - - parse_get_string(parse,argument,StringSize); - - if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); - - if (FALSE) { - - } else if (my_string_equal(option,"cpuload")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=0); - - if (n >= 0) uci->cpu = ((double)n) / 1000.0; - - } else if (my_string_equal(option,"currline")) { - - ASSERT(!my_string_empty(argument)); - - line_from_can(uci->current_line,uci->board,argument,LineSize); - - } else if (my_string_equal(option,"currmove")) { - - ASSERT(!my_string_empty(argument)); - - uci->root_move = move_from_can(argument,uci->board); - ASSERT(uci->root_move!=MoveNone); - - } else if (my_string_equal(option,"currmovenumber")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=1&&n<=uci->root_move_nb); - - if (n >= 1 && n <= uci->root_move_nb) { - uci->root_move_pos = n - 1; - ASSERT(uci->root_move_pos>=0&&uci->root_move_posroot_move_nb); - } - - } else if (my_string_equal(option,"depth")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=1); - - if (n >= 0) { - if (n > uci->depth) event |= EVENT_DEPTH; - uci->depth = n; - } - - } else if (my_string_equal(option,"hashfull")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=0); - - if (n >= 0) uci->hash = ((double)n) / 1000.0; - - } else if (my_string_equal(option,"multipv")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - multipvline=n; - - ASSERT(n>=1); - - } else if (my_string_equal(option,"nodes")) { - - ASSERT(!my_string_empty(argument)); - - ln = my_atoll(argument); - ASSERT(ln>=0); - - if (ln >= 0) uci->node_nb = ln; - - } else if (my_string_equal(option,"nps")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=0); - - if (n >= 0) uci->speed = ((double)n); - - } else if (my_string_equal(option,"pv")) { - - ASSERT(!my_string_empty(argument)); - - line_from_can(uci->pv,uci->board,argument,LineSize); - event |= EVENT_PV; - - } else if (my_string_equal(option,"refutation")) { - - ASSERT(!my_string_empty(argument)); - - line_from_can(uci->pv,uci->board,argument,LineSize); - - } else if (my_string_equal(option,"score")) { - - ASSERT(!my_string_empty(argument)); - - parse_score(uci,argument); - - } else if (my_string_equal(option,"seldepth")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=0); - - if (n >= 0) uci->sel_depth = n; - - } else if (my_string_equal(option,"string")) { - if(my_string_case_equal(argument,"DrawOffer")){ - event |= EVENT_DRAW; - }else if(my_string_case_equal(argument,"Resign")){ - event |= EVENT_RESIGN; - }else{ - snprintf(uci->info,sizeof(uci->info),"%s",argument); - uci->info[sizeof(uci->info)-1]='\0'; - event|=EVENT_INFO; - } - // TODO: argument to EOS - - ASSERT(!my_string_empty(argument)); - - } else if (my_string_equal(option,"tbhits")) { - - ASSERT(!my_string_empty(argument)); - - ln = my_atoll(argument); - ASSERT(ln>=0); - - } else if (my_string_equal(option,"time")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n>=0); - - if (n >= 0) uci->time = ((double)n) / 1000.0; - - } else { - - my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); - // This should probably be protected - // by a "WorkAround" option. - snprintf(uci->info,sizeof(uci->info),"%s %s",option,argument); - uci->info[sizeof(uci->info)-1]='\0'; - event|=EVENT_INFO; - } - } - - parse_close(parse); - - - // code by HGM - if ((event & EVENT_PV) != 0) { - uci->best_score = uci->score; - uci->best_sel_depth = uci->sel_depth; - line_copy(uci->best_pv,uci->pv); - } - if(uci->depth < uci->best_depth){ - // ignore lines of lower depth - event &= ~EVENT_PV; - } else { - if(uci->depth > uci->best_depth) { - // clear stack when we start new depth - uci->multipvSP = 0; - } - uci->best_depth = uci->depth; - if(multipvline >= 1) { - int i; - for(i=0; imultipvSP; i++) { - if(uci->score == uci->multipvScore[i] && uci->pv[0] == uci->multipvMove[i]) { - event &= ~EVENT_PV; // ignore duplicates - } - } - if(event & EVENT_PV){ - // line is new, try to add to stack - if(uci->multipvSPmultipvMove[uci->multipvSP] = uci->pv[0]; - uci->multipvScore[uci->multipvSP] = uci->score; - uci->multipvSP++; - }else{ - my_fatal("parse_info(): multipv stack overflow."); - } - } - } - } - - - return event; -} - -// parse_option() - -static void parse_option(uci_t * uci, const char string[]) { - - option_t opt[1]; - parse_t parse[1]; - char command[StringSize]; - char option[StringSize]; - char argument[StringSize]; - - ASSERT(uci!=NULL); - ASSERT(string!=NULL); - - // init - - strcpy(command,"option"); - - memset(opt,0,sizeof(option_t)); - - my_string_set(&opt->value,""); - my_string_set(&opt->name,""); - my_string_set(&opt->default_,""); - my_string_set(&opt->max,""); - my_string_set(&opt->min,""); - my_string_set(&opt->type,""); - opt->var_nb=0; - opt->mode=0; - - parse_open(parse,string); - parse_add_keyword(parse,"default"); - parse_add_keyword(parse,"max"); - parse_add_keyword(parse,"min"); - parse_add_keyword(parse,"name"); - parse_add_keyword(parse,"type"); - parse_add_keyword(parse,"var"); - - // loop - - while (parse_get_word(parse,option,StringSize)) { - parse_get_string(parse,argument,StringSize); - if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); - - if (FALSE) { - - } else if (my_string_equal(option,"default")) { - - // ASSERT(!my_string_empty(argument)); // HACK for Pepito - - if (!my_string_empty(argument)) { - my_string_set(&opt->default_,argument); - my_string_set(&opt->value,argument); - } - - } else if (my_string_equal(option,"max")) { - - ASSERT(!my_string_empty(argument)); - my_string_set(&opt->max,argument); - - } else if (my_string_equal(option,"min")) { - - ASSERT(!my_string_empty(argument)); - my_string_set(&opt->min,argument); - - } else if (my_string_equal(option,"name")) { - - ASSERT(!my_string_empty(argument)); - - if (!my_string_empty(argument)) { - my_string_set(&opt->name,argument); - } - - } else if (my_string_equal(option,"type")) { - - ASSERT(!my_string_empty(argument)); - my_string_set(&opt->type,argument); - - } else if (my_string_equal(option,"var")) { - - ASSERT(!my_string_empty(argument)); - my_string_set(&opt->var[opt->var_nb++],argument); - if(opt->var_nb==VarNb) break; - - } else { - - my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); - } - } - - parse_close(parse); - - apply_UCI3_heuristics(opt); - option_insert(uci->option,opt); - option_free(opt); - - if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_); -} - -// parse_score() - -static void parse_score(uci_t * uci, const char string[]) { - - parse_t parse[1]; - char command[StringSize]; - char option[StringSize]; - char argument[StringSize]; - int n; - - ASSERT(uci_is_ok(uci)); - ASSERT(string!=NULL); - - // init - - strcpy(command,"score"); - - parse_open(parse,string); - parse_add_keyword(parse,"cp"); - parse_add_keyword(parse,"lowerbound"); - parse_add_keyword(parse,"mate"); - parse_add_keyword(parse,"upperbound"); - - // loop - - while (parse_get_word(parse,option,StringSize)) { - - parse_get_string(parse,argument,StringSize); - - if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); - - if (FALSE) { - - } else if (my_string_equal(option,"cp")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - - uci->score = n; - - } else if (my_string_equal(option,"lowerbound")) { - - ASSERT(my_string_empty(argument)); - - } else if (my_string_equal(option,"mate")) { - - ASSERT(!my_string_empty(argument)); - - n = atoi(argument); - ASSERT(n!=0); - - uci->score = mate_score(n); - - } else if (my_string_equal(option,"upperbound")) { - - ASSERT(my_string_empty(argument)); - - } else { - - my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); - } - } - - parse_close(parse); -} - -// mate_score() - -static int mate_score(int dist) { - - ASSERT(dist!=0); - - if (FALSE) { - } else if (dist > 0) { - return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1; - } else if (dist < 0) { - return -option_get_int(Option,"MateScore") + (-dist) * 2; - } - - return 0; -} - -// end of uci.cpp - + +// uci.c + +// includes + +#include +#include +#include +#include + +#include "board.h" +#include "engine.h" +#include "gui.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "line.h" +#include "uci.h" + + +// constants + +static const bool UseDebug = FALSE; + +// variables + +uci_t Uci[1]; + +// Hopefully the following confusion is temporary +// Normally we should check for the engine name but this is a hack anyway +// Some of there where provided by Marc Lacrosse + +const char * thread_options[]={ + "number of threads", // toga + "number threads", // Deep Learning Toga + "threads", // glaurung, zappa, cyclone, grapefruit, + // Deep Shredder, Deep Junior, bright + "core threads", // HIARCS + "max cpus", // rybka + "cpus", // Deep Sjeng, Fruit2.3.5 + "maxthreads", // Naum + NULL +}; + +// prototypes + +static bool uci_is_ok (const uci_t * uci); + +static int parse_bestmove (uci_t * uci, const char string[]); +static void parse_id (uci_t * uci, const char string[]); +static int parse_info (uci_t * uci, const char string[]); +static void parse_option (uci_t * uci, const char string[]); +static void parse_score (uci_t * uci, const char string[]); + +static int mate_score (int dist); + +// functions + + +// uci_adapt_UCI3() + +static void apply_UCI3_heuristics(option_t *opt){ + if(option_get_int(Option,"UCIVersion")>2){ + return; + } + if(!my_string_equal(opt->type,"string")){ + return; + } + if(!strncmp(opt->name,"UCI_",4)){ + return; + } + if(my_string_case_contains(opt->name,"file")){ + my_string_set(&opt->type,"file"); + return; + } + if(my_string_case_contains(opt->name,"path")){ + my_string_set(&opt->type,"path"); + return; + } +} + +// uci_set_threads() + +void uci_set_threads(uci_t * uci, int n) { + const char *thread_option=uci_thread_option(uci); + ASSERT(n>=1); + if(thread_option){ + uci_send_option(uci,thread_option,"%d",n); + } +} + + +const char * uci_thread_option(uci_t * uci){ + const char **p = thread_options; + const char *thread_option; + option_t *opt; + while((thread_option = *(p++))){ + if((opt=option_find(uci->option,thread_option))){ + return opt->name; + break; + } + } + return NULL; +} + +// uci_is_ok() + +static bool uci_is_ok(const uci_t * uci) { + + if (uci == NULL) return FALSE; + if (uci->engine == NULL) return FALSE; + if (!option_is_ok(uci->option)) return FALSE; + return TRUE; +} + +// uci_open() + +void uci_open(uci_t * uci, engine_t * engine) { + + char string[StringSize]; + int event; + + ASSERT(uci!=NULL); + ASSERT(engine!=NULL); + + // init + + uci->engine = engine; + + uci->name = NULL; + my_string_set(&uci->name,""); + uci->author = NULL; + my_string_set(&uci->author,""); + option_init(uci->option); + + uci->ready_nb = 0; + uci->searching = 0; + uci->pending_nb = 0; + uci->multipv_mode = FALSE; + board_start(uci->board); + uci_clear(uci); + + // send "uci" and wait for "uciok" + + engine_send(uci->engine,"uci"); + + do { + engine_get(uci->engine,string); + // Handle the case that the engine is really a WB engine somewhat gracefully. + if((strstr(string,"Illegal") || strstr(string,"Error")) + &&strstr(string,"uci")){ + my_fatal("uci_open(): Not a UCI engine.\n"); + } + event = uci_parse(uci,string); + } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0); +} + +// uci_close() + +void uci_close(uci_t * uci) { + + ASSERT(uci_is_ok(uci)); + engine_close(uci->engine); + uci->engine = NULL; + my_string_clear(&uci->name); + my_string_clear(&uci->author); + + option_clear(uci->option); +} + +// uci_clear() + +void uci_clear(uci_t * uci) { + + ASSERT(uci_is_ok(uci)); + + ASSERT(!uci->searching); + + uci->best_move = MoveNone; + uci->ponder_move = MoveNone; + + uci->score = 0; + uci->depth = 0; + uci->sel_depth = 0; + line_clear(uci->pv); + + uci->best_score = 0; + uci->best_depth = 0; + uci->best_sel_depth = 0; + line_clear(uci->best_pv); +// make the default 1 instead of 0 so that info lines can be recognized by their node number 0 + uci->node_nb = 1; + uci->time = 0.0; + uci->speed = 0.0; + uci->cpu = 0.0; + uci->hash = 0.0; + line_clear(uci->current_line); + + uci->root_move = MoveNone; + uci->root_move_pos = 0; + uci->root_move_nb = board_mobility(uci->board); + + uci->multipvSP=0; +} + +// uci_send_isready() + +void uci_send_isready(uci_t * uci) { + + ASSERT(uci!=NULL); + + engine_send(uci->engine,"isready"); + uci->ready_nb++; +} + +// uci_send_isready_sync() + +void uci_send_isready_sync(uci_t * uci) { + + char string[StringSize]; + int event; + + ASSERT(uci_is_ok(uci)); + + // send "isready" and wait for "readyok" + + uci_send_isready(uci); + + do { + engine_get(uci->engine,string); + event = uci_parse(uci,string); + } while (!engine_eof(Engine) && (event & EVENT_READY) == 0); +} + +// uci_send_stop() + +void uci_send_stop(uci_t * uci) { + + ASSERT(uci_is_ok(uci)); + + ASSERT(uci->searching); + ASSERT(uci->pending_nb>=1); + + engine_send(Engine,"stop"); + uci->searching = FALSE; +} + +// uci_send_stop_sync() + +void uci_send_stop_sync(uci_t * uci) { + + char string[StringSize]; + int event; + + ASSERT(uci_is_ok(uci)); + + ASSERT(uci->searching); + ASSERT(uci->pending_nb>=1); + + // send "stop" and wait for "bestmove" + + uci_send_stop(uci); + + do { + engine_get(uci->engine,string); + event = uci_parse(uci,string); + } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0); +} + +// uci_send_ucinewgame() + +void uci_send_ucinewgame(uci_t * uci) { + + ASSERT(uci!=NULL); + + if (option_get_int(Option,"UCIVersion") >= 2) { + engine_send(uci->engine,"ucinewgame"); + } +} + +// uci_send_option() + +bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) { + + char value[FormatBufferSize]; + option_t * opt; + bool found=FALSE; + + ASSERT(uci_is_ok(uci)); + ASSERT(option!=NULL); + ASSERT(format!=NULL); + + // format + + CONSTRUCT_ARG_STRING(format,value); + + if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value); + + opt=option_find(uci->option,option); + if(opt){ + found=TRUE; + if(!IS_BUTTON(opt->type)){ + if(!my_string_equal(opt->value,value)){ + engine_send(uci->engine,"setoption name %s value %s", + opt->name,value); + my_string_set(&opt->value,value); + }else{ + my_log("POLYGLOT Not sending option \"%s\" since it " + "already has the correct value.\n",opt->name); + } + }else{ + engine_send(uci->engine,"setoption name %s",opt->name); + } + } + return found; +} + +// uci_parse() + +int uci_parse(uci_t * uci, const char string[]) { + + int event; + parse_t parse[1]; + char command[StringSize]; + char argument[StringSize]; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + event = EVENT_NONE; + + // parse + + parse_open(parse,string); + + if (parse_get_word(parse,command,StringSize)) { + + parse_get_string(parse,argument,StringSize); + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument); + + if (FALSE) { + + } else if (my_string_equal(command,"bestmove")) { + + // search end + + ASSERT(uci->pending_nb>0); + + if (uci->searching && uci->pending_nb == 1) { + + // current search + + uci->searching = FALSE; + uci->pending_nb--; + + event = parse_bestmove(uci,argument); // updates uci->best_move, uci->ponder_move + + } else { + + // obsolete search + + if (uci->pending_nb > 0) { + uci->pending_nb--; + if (uci->pending_nb == 0) event = EVENT_STOP; + } + } + + } else if (my_string_equal(command,"id")) { + + parse_id(uci,argument); + + } else if (my_string_equal(command,"info")) { + + // search information + + if (uci->searching && uci->pending_nb == 1) { // current search + event = parse_info(uci,argument); + } + + } else if (my_string_equal(command,"option")) { + + parse_option(uci,argument); + + } else if (my_string_equal(command,"readyok")) { + + // engine is ready + + ASSERT(uci->ready_nb>0); + + if (uci->ready_nb > 0) { + uci->ready_nb--; + if (uci->ready_nb == 0) event = EVENT_READY; + } + + } else if (my_string_equal(command,"uciok")) { + + event = EVENT_UCI; + + } else { + + if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command); + } + } + + parse_close(parse); + + return event; +} + +// parse_bestmove() + +static int parse_bestmove(uci_t * uci, const char string[]) { + + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + board_t board[1]; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + strcpy(command,"bestmove"); + + parse_open(parse,string); + parse_add_keyword(parse,"ponder"); + + // bestmove + + uci->bestmove[0]='\0'; + if (!parse_get_string(parse,argument,StringSize)) { + strcpy(uci->bestmove,"nomove"); + return EVENT_ILLEGAL_MOVE; +// my_fatal("parse_bestmove(): missing argument\n"); + } + strncpy(uci->bestmove,argument,UciStringSize); + uci->bestmove[UciStringSize-1]='\0'; + + uci->best_move = move_from_can(argument,uci->board); + if (uci->best_move == MoveNone) { + return EVENT_ILLEGAL_MOVE; +// my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); + } + + if(!move_is_legal(uci->best_move,uci->board)){ + return EVENT_ILLEGAL_MOVE; + } + ASSERT(uci->best_move!=MoveNone); + ASSERT(move_is_legal(uci->best_move,uci->board)); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"ponder")) { + + ASSERT(!my_string_empty(argument)); + + board_copy(board,uci->board); + move_do(board,uci->best_move); + + uci->ponder_move = move_from_can(argument,board); + + // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); + + ASSERT(uci->ponder_move!=MoveNone); + ASSERT(move_is_legal(uci->ponder_move,board)); + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + return EVENT_MOVE; +} + +// parse_id() + +static void parse_id(uci_t * uci, const char string[]) { + + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + + ASSERT(uci!=NULL); + ASSERT(string!=NULL); + + // init + + strcpy(command,"id"); + + parse_open(parse,string); + parse_add_keyword(parse,"author"); + parse_add_keyword(parse,"name"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + } else if (my_string_equal(option,"author")) { + ASSERT(!my_string_empty(argument)); + my_string_set(&uci->author,argument); + } else if (my_string_equal(option,"name")) { + ASSERT(!my_string_empty(argument)); + my_string_set(&uci->name,argument); + } else { + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author); +} + +// parse_info() + +static int parse_info(uci_t * uci, const char string[]) { + + int event; + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + int n; + int multipvline=0; + sint64 ln; + + + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + event = EVENT_NONE; + + strcpy(command,"info"); + + parse_open(parse,string); + parse_add_keyword(parse,"cpuload"); + parse_add_keyword(parse,"currline"); + parse_add_keyword(parse,"currmove"); + parse_add_keyword(parse,"currmovenumber"); + parse_add_keyword(parse,"depth"); + parse_add_keyword(parse,"hashfull"); + parse_add_keyword(parse,"multipv"); + parse_add_keyword(parse,"nodes"); + parse_add_keyword(parse,"nps"); + parse_add_keyword(parse,"pv"); + parse_add_keyword(parse,"refutation"); + parse_add_keyword(parse,"score"); + parse_add_keyword(parse,"seldepth"); + parse_add_keyword(parse,"string"); + parse_add_keyword(parse,"tbhits"); + parse_add_keyword(parse,"time"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"cpuload")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->cpu = ((double)n) / 1000.0; + + } else if (my_string_equal(option,"currline")) { + + ASSERT(!my_string_empty(argument)); + + line_from_can(uci->current_line,uci->board,argument,LineSize); + + } else if (my_string_equal(option,"currmove")) { + + ASSERT(!my_string_empty(argument)); + + uci->root_move = move_from_can(argument,uci->board); + ASSERT(uci->root_move!=MoveNone); + + } else if (my_string_equal(option,"currmovenumber")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=1&&n<=uci->root_move_nb); + + if (n >= 1 && n <= uci->root_move_nb) { + uci->root_move_pos = n - 1; + ASSERT(uci->root_move_pos>=0&&uci->root_move_posroot_move_nb); + } + + } else if (my_string_equal(option,"depth")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=1); + + if (n >= 0) { + if (n > uci->depth) event |= EVENT_DEPTH; + uci->depth = n; + } + + } else if (my_string_equal(option,"hashfull")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->hash = ((double)n) / 1000.0; + + } else if (my_string_equal(option,"multipv")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + multipvline=n; + + ASSERT(n>=1); + + } else if (my_string_equal(option,"nodes")) { + + ASSERT(!my_string_empty(argument)); + + ln = my_atoll(argument); + ASSERT(ln>=0); + + if (ln >= 0) uci->node_nb = ln; + + } else if (my_string_equal(option,"nps")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->speed = ((double)n); + + } else if (my_string_equal(option,"pv")) { + + ASSERT(!my_string_empty(argument)); + line_from_can(uci->pv,uci->board,argument,LineSize); + event |= EVENT_PV; + + } else if (my_string_equal(option,"refutation")) { + + ASSERT(!my_string_empty(argument)); + + line_from_can(uci->pv,uci->board,argument,LineSize); + + } else if (my_string_equal(option,"score")) { + + ASSERT(!my_string_empty(argument)); + + parse_score(uci,argument); + + } else if (my_string_equal(option,"seldepth")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->sel_depth = n; + + } else if (my_string_equal(option,"string")) { + if(my_string_case_equal(argument,"DrawOffer")){ + event |= EVENT_DRAW; + }else if(my_string_case_equal(argument,"Resign")){ + event |= EVENT_RESIGN; + }else{ + snprintf(uci->info,sizeof(uci->info),"%s",argument); + uci->info[sizeof(uci->info)-1]='\0'; + event|=EVENT_INFO; + } + // TODO: argument to EOS + + ASSERT(!my_string_empty(argument)); + + } else if (my_string_equal(option,"tbhits")) { + + ASSERT(!my_string_empty(argument)); + + ln = my_atoll(argument); + ASSERT(ln>=0); + + } else if (my_string_equal(option,"time")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->time = ((double)n) / 1000.0; + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + // This should probably be protected + // by a "WorkAround" option. + snprintf(uci->info,sizeof(uci->info),"%s %s",option,argument); + uci->info[sizeof(uci->info)-1]='\0'; + event|=EVENT_INFO; + } + } + + parse_close(parse); + + + // code by HGM + if ((event & EVENT_PV) != 0) { + uci->best_score = uci->score; + uci->best_sel_depth = uci->sel_depth; + line_copy(uci->best_pv,uci->pv); + } + if(uci->depth < uci->best_depth){ + // ignore lines of lower depth + event &= ~EVENT_PV; + } else { + if(uci->depth > uci->best_depth) { + // clear stack when we start new depth + uci->multipvSP = 0; + } + uci->best_depth = uci->depth; + if(multipvline >= 1) { + int i; + for(i=0; imultipvSP; i++) { + if(uci->score == uci->multipvScore[i] && uci->pv[0] == uci->multipvMove[i]) { + event &= ~EVENT_PV; // ignore duplicates + } + } + if(event & EVENT_PV){ + // line is new, try to add to stack + if(uci->multipvSPmultipvMove[uci->multipvSP] = uci->pv[0]; + uci->multipvScore[uci->multipvSP] = uci->score; + uci->multipvSP++; + }else{ + my_fatal("parse_info(): multipv stack overflow."); + } + } + } + } + + + return event; +} + +// parse_option() + +static void parse_option(uci_t * uci, const char string[]) { + + option_t opt[1]; + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + + ASSERT(uci!=NULL); + ASSERT(string!=NULL); + + // init + + strcpy(command,"option"); + + memset(opt,0,sizeof(option_t)); + + my_string_set(&opt->value,""); + my_string_set(&opt->name,""); + my_string_set(&opt->default_,""); + my_string_set(&opt->max,""); + my_string_set(&opt->min,""); + my_string_set(&opt->type,""); + opt->var_nb=0; + opt->mode=0; + + parse_open(parse,string); + parse_add_keyword(parse,"default"); + parse_add_keyword(parse,"max"); + parse_add_keyword(parse,"min"); + parse_add_keyword(parse,"name"); + parse_add_keyword(parse,"type"); + parse_add_keyword(parse,"var"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + parse_get_string(parse,argument,StringSize); + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"default")) { + + // ASSERT(!my_string_empty(argument)); // HACK for Pepito + + if (!my_string_empty(argument)) { + my_string_set(&opt->default_,argument); + my_string_set(&opt->value,argument); + } + + } else if (my_string_equal(option,"max")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->max,argument); + + } else if (my_string_equal(option,"min")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->min,argument); + + } else if (my_string_equal(option,"name")) { + + ASSERT(!my_string_empty(argument)); + + if (!my_string_empty(argument)) { + my_string_set(&opt->name,argument); + } + + } else if (my_string_equal(option,"type")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->type,argument); + + } else if (my_string_equal(option,"var")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->var[opt->var_nb++],argument); + if(opt->var_nb==VarNb) break; + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + apply_UCI3_heuristics(opt); + option_insert(uci->option,opt); + option_free(opt); + + if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_); +} + +// parse_score() + +static void parse_score(uci_t * uci, const char string[]) { + + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + int n; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + strcpy(command,"score"); + + parse_open(parse,string); + parse_add_keyword(parse,"cp"); + parse_add_keyword(parse,"lowerbound"); + parse_add_keyword(parse,"mate"); + parse_add_keyword(parse,"upperbound"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"cp")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + + uci->score = n; + + } else if (my_string_equal(option,"lowerbound")) { + + ASSERT(my_string_empty(argument)); + + } else if (my_string_equal(option,"mate")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n!=0); + + uci->score = mate_score(n); + + } else if (my_string_equal(option,"upperbound")) { + + ASSERT(my_string_empty(argument)); + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); +} + +// mate_score() + +static int mate_score(int dist) { + + ASSERT(dist!=0); + + if (FALSE) { + } else if (dist > 0) { + return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1; + } else if (dist < 0) { + return -option_get_int(Option,"MateScore") + (-dist) * 2; + } + + return 0; +} + +// end of uci.cpp + diff --git a/uci.h b/uci.h index 3e6bacf..cac77df 100644 --- a/uci.h +++ b/uci.h @@ -1,109 +1,109 @@ - -// uci.h - -#ifndef UCI_H -#define UCI_H - -// includes - -#include "board.h" -#include "engine.h" -#include "line.h" -#include "move.h" -#include "option.h" -#include "util.h" - -// macros - -// I need to make a uniform string type. - -#define UciStringSize 4096 -#define MultiPVStackSize 256 - -// types - -typedef struct { - - engine_t * engine; - - const char * name; - const char * author; - - option_list_t option[1]; - - bool ready; - int ready_nb; - - bool searching; - int pending_nb; - - board_t board[1]; - - int best_move; - int ponder_move; - - int score; - int depth; - int sel_depth; - move_t pv[LineSize]; - - int best_score; - int best_depth; - int best_sel_depth; - move_t best_pv[LineSize]; - char bestmove[UciStringSize]; - - sint64 node_nb; - double time; - double speed; - double cpu; - double hash; - move_t current_line[LineSize]; - - int root_move; - int root_move_pos; - int root_move_nb; - bool multipv_mode; - int multipvSP; - int multipvScore[MultiPVStackSize]; - move_t multipvMove[MultiPVStackSize]; - char info[UciStringSize]; -} uci_t; - -typedef enum { - EVENT_NONE = 0, - EVENT_UCI = 1 << 0, - EVENT_READY = 1 << 1, - EVENT_STOP = 1 << 2, - EVENT_MOVE = 1 << 3, - EVENT_PV = 1 << 4, - EVENT_DEPTH = 1 << 5, - EVENT_DRAW = 1 << 6, - EVENT_RESIGN = 1 << 7, - EVENT_ILLEGAL_MOVE = 1 << 8, - EVENT_INFO = 1 << 9 -} dummy_event_t; - -// variables - -extern uci_t Uci[1]; - -// functions - -extern void uci_open (uci_t * uci, engine_t * engine); -extern void uci_send_isready (uci_t * uci); -extern void uci_send_isready_sync (uci_t * uci); -extern void uci_send_stop (uci_t * uci); -extern void uci_send_stop_sync (uci_t * uci); -extern void uci_send_ucinewgame (uci_t * uci); -extern void uci_set_threads (uci_t * uci, int n); -extern const char * uci_thread_option(uci_t * uci); -extern bool uci_send_option (uci_t * uci, const char option[], const char format[], ...); -extern void uci_close (uci_t * uci); -extern void uci_clear (uci_t * uci); -extern int uci_parse (uci_t * uci, const char string[]); - -#endif // !defined UCI_H - -// end of uci.h - + +// uci.h + +#ifndef UCI_H +#define UCI_H + +// includes + +#include "board.h" +#include "engine.h" +#include "line.h" +#include "move.h" +#include "option.h" +#include "util.h" + +// macros + +// I need to make a uniform string type. + +#define UciStringSize 4096 +#define MultiPVStackSize 256 + +// types + +typedef struct { + + engine_t * engine; + + const char * name; + const char * author; + + option_list_t option[1]; + + bool ready; + int ready_nb; + + bool searching; + int pending_nb; + + board_t board[1]; + + int best_move; + int ponder_move; + + int score; + int depth; + int sel_depth; + move_t pv[LineSize]; + + int best_score; + int best_depth; + int best_sel_depth; + move_t best_pv[LineSize]; + char bestmove[UciStringSize]; + + sint64 node_nb; + double time; + double speed; + double cpu; + double hash; + move_t current_line[LineSize]; + + int root_move; + int root_move_pos; + int root_move_nb; + bool multipv_mode; + int multipvSP; + int multipvScore[MultiPVStackSize]; + move_t multipvMove[MultiPVStackSize]; + char info[UciStringSize]; +} uci_t; + +typedef enum { + EVENT_NONE = 0, + EVENT_UCI = 1 << 0, + EVENT_READY = 1 << 1, + EVENT_STOP = 1 << 2, + EVENT_MOVE = 1 << 3, + EVENT_PV = 1 << 4, + EVENT_DEPTH = 1 << 5, + EVENT_DRAW = 1 << 6, + EVENT_RESIGN = 1 << 7, + EVENT_ILLEGAL_MOVE = 1 << 8, + EVENT_INFO = 1 << 9 +} dummy_event_t; + +// variables + +extern uci_t Uci[1]; + +// functions + +extern void uci_open (uci_t * uci, engine_t * engine); +extern void uci_send_isready (uci_t * uci); +extern void uci_send_isready_sync (uci_t * uci); +extern void uci_send_stop (uci_t * uci); +extern void uci_send_stop_sync (uci_t * uci); +extern void uci_send_ucinewgame (uci_t * uci); +extern void uci_set_threads (uci_t * uci, int n); +extern const char * uci_thread_option(uci_t * uci); +extern bool uci_send_option (uci_t * uci, const char option[], const char format[], ...); +extern void uci_close (uci_t * uci); +extern void uci_clear (uci_t * uci); +extern int uci_parse (uci_t * uci, const char string[]); + +#endif // !defined UCI_H + +// end of uci.h + diff --git a/util.c b/util.c index c2dec6b..c1d267d 100644 --- a/util.c +++ b/util.c @@ -1,526 +1,526 @@ - -// util.c - -// includes - -#ifdef _WIN32 -#include -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef _MSC_VER -#include -#endif - -#include "main.h" -#include "util.h" -#include "gui.h" - -// macros - -#define StringSize 4096 - -// variables - -static bool Error; - -FILE * LogFile=NULL; - -// functions - -// util_init() - -void util_init() { - - Error = FALSE; - - // init log file - - LogFile = NULL; - - // switch file buffering off - - setbuf(stdin,NULL); - setbuf(stdout,NULL); -} - -// my_random_init() - -void my_random_init() { - srand(time(NULL)); -} - -// my_random_int() - -int my_random_int(int n) { - - int r; - - ASSERT(n>0); - - r = ((int)floor(my_random_double()*((double)n))); - ASSERT(r>=0&&r=0.0&&r<1.0); - - return r; -} - -// my_atoll() - -sint64 my_atoll(const char string[]) { - - sint64 n; - - sscanf(string,S64_FORMAT,&n); - - return n; -} - -// my_round() - -int my_round(double x) { - - return ((int)floor(x+0.5)); -} - -// my_malloc() - -void * my_malloc(size_t size) { - - void * address; - - ASSERT(size>0); - - address = malloc(size); - if (address == NULL) my_fatal("my_malloc(): malloc(): %s\n",strerror(errno)); - - return address; -} - -// my_realloc() - -void * my_realloc(void * address, size_t size) { - - ASSERT(address!=NULL); - ASSERT(size>0); - - address = realloc(address,size); - if (address == NULL) my_fatal("my_realloc(): realloc(): %s\n",strerror(errno)); - - return address; -} - -// my_free() - -void my_free(void * address) { - - ASSERT(address!=NULL); - - free(address); -} - -// my_log_open() - -void my_log_open(const char file_name[]) { - - ASSERT(file_name!=NULL); - - LogFile = fopen(file_name,"a"); -#ifndef _WIN32 -//line buffering doesn't work too well in MSVC and/or windows - if (LogFile != NULL) setvbuf(LogFile,NULL,_IOLBF,0); // line buffering -#endif - if(LogFile!=NULL){ - my_log("POLYGLOT *** LOGFILE OPENED ***\n"); - } - -} - -// my_log_close() - -void my_log_close() { - - if (LogFile != NULL) fclose(LogFile); - LogFile=NULL; -} - -// my_log() - -void my_log(const char format[], ...) { - - char string[FormatBufferSize]; - - ASSERT(format!=NULL); - -// format - - CONSTRUCT_ARG_STRING(format,string); - - - if (LogFile != NULL) { - fprintf(LogFile,"%.3f %s",now_real(),string); -#ifdef _WIN32 - fflush(LogFile); -#endif - } -} - -// my_fatal() - -void my_fatal(const char format[], ...) { - - char string[FormatBufferSize]; - - ASSERT(format!=NULL); - -// format - - CONSTRUCT_ARG_STRING(format,string); - - my_log("POLYGLOT %s",string); - // This should be gui_send but this does not work. - // Why? - - printf("tellusererror POLYGLOT: %s",string); - - if (Error) { // recursive error - my_log("POLYGLOT *** RECURSIVE ERROR ***\n"); - exit(EXIT_FAILURE); - // abort(); - } else { - Error = TRUE; - quit(); - } -} - -// my_file_read_line() - -bool my_file_read_line(FILE * file, char string[], int size) { - - int src, dst; - int c; - - ASSERT(file!=NULL); - ASSERT(string!=NULL); - ASSERT(size>0); - - if (fgets(string,size,file) == NULL) { - if (feof(file)) { - return FALSE; - } else { // error - my_fatal("my_file_read_line(): fgets(): %s\n",strerror(errno)); - } - } - - // remove CRs and LFs - - src = 0; - dst = 0; - - while ((c=string[src++]) != '\0') { - if (c != '\r' && c != '\n') string[dst++] = c; - } - - string[dst] = '\0'; - - return TRUE; -} - -// my_file_join() - -void my_path_join(char *join_path, const char *path, const char *file){ - char separator; -#ifdef _WIN32 - separator='\\'; -#else - separator='/'; -#endif - snprintf(join_path,StringSize,"%s%c%s",path,separator,file); - join_path[StringSize-1]='\0'; -} - -// my_mkdir() - -int my_mkdir(const char *path){ - int ret; -#ifdef _WIN32 - ret=_mkdir(path); -#else - ret=mkdir(path,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); -#endif - return ret; -} - - -// my_string_empty() - -bool my_string_empty(const char string[]) { - - return string == NULL || string[0] == '\0'; -} - -// my_string_whitespace() - -bool my_string_whitespace(const char string[]){ - int pos=0; - while(string[pos]!='\0'){ - if(string[pos]!=' ' && string[pos]!='\t'){ - return FALSE; - } - pos++; - } - return TRUE; -} - -// my_string_equal() - -bool my_string_equal(const char string_1[], const char string_2[]) { - - ASSERT(string_1!=NULL); - ASSERT(string_2!=NULL); - - return strcmp(string_1,string_2) == 0; -} - -// my_string_case_equal() - -bool my_string_case_equal(const char string_1[], const char string_2[]) { - - int c1, c2; - - ASSERT(string_1!=NULL); - ASSERT(string_2!=NULL); - - while (TRUE) { - - c1 = *string_1++; - c2 = *string_2++; - - if (tolower(c1) != tolower(c2)) return FALSE; - if (c1 == '\0') return TRUE; - } - - return FALSE; -} - -// my_strtolower() - -void my_string_tolower(char *dst, const char *src){ - int c; - ASSERT(src!=NULL); - ASSERT(dst!=NULL); - while((c=*(src++))){ - *dst=tolower(c); - dst++; - } - *(dst++)='\0'; -} - -// my_string_case_contains() - -const char* my_string_case_contains(const char string_1[], const char string_2[]){ - - char tmp1[StringSize]; - char tmp2[StringSize]; - char *where; - - - ASSERT(string_1!=NULL); - ASSERT(string_2!=NULL); - - my_string_tolower(tmp1,string_1); - my_string_tolower(tmp2,string_2); - - where=strstr(tmp1,tmp2); - if(where){ - return string_1+(where-tmp1); - } - return NULL; - - -} - - -// my_strdup() - -char * my_strdup(const char string[]) { - - char * address; - - ASSERT(string!=NULL); - - // strdup() is not ANSI C - - address = (char *) my_malloc(strlen(string)+1); - strcpy(address,string); - - return address; -} - -// my_string_clear() - -void my_string_clear(const char * * variable) { - - ASSERT(variable!=NULL); - - if (*variable != NULL) { - my_free((void*)(*variable)); - *variable = NULL; - } -} - -// my_string_set() - -void my_string_set(const char * * variable, const char string[]) { - - ASSERT(variable!=NULL); - ASSERT(string!=NULL); - - if (*variable != NULL) my_free((void*)(*variable)); - *variable = my_strdup(string); -} - -// now_real() - -double now_real() { -#ifndef _WIN32 - struct timeval tv[1]; - struct timezone tz[1]; - - tz->tz_minuteswest = 0; - tz->tz_dsttime = 0; // DST_NONE not declared in linux - - if (gettimeofday(tv,tz) == -1) { - my_fatal("now_real(): gettimeofday(): %s\n",strerror(errno)); - } - - return tv->tv_sec + tv->tv_usec * 1E-6; -#else - struct _timeb timeptr; - _ftime(&timeptr); - return(timeptr.time+((double)timeptr.millitm)/1000.0); -// return (double) GetTickCount() / 1000.0; // we can do better here:-) -#endif -} - - -// my_timer_reset() - -void my_timer_reset(my_timer_t * timer) { - - ASSERT(timer!=NULL); - - timer->start_real = 0.0; - timer->elapsed_real = 0.0; - timer->running = FALSE; -} - -// my_timer_start() - -void my_timer_start(my_timer_t * timer) { -// timer->start_real = 0.0; - timer->elapsed_real = 0.0; -// timer->running = FALSE; - ASSERT(timer!=NULL); - - timer->running = TRUE; - timer->start_real = now_real(); -} - -// my_timer_stop() - -void my_timer_stop(my_timer_t * timer) { - - ASSERT(timer!=NULL); - - ASSERT(timer->running); - - timer->elapsed_real += now_real() - timer->start_real; - timer->start_real = 0.0; - timer->running = FALSE; -} - -// my_timer_elapsed_real() - -double my_timer_elapsed_real(const my_timer_t * timer) { - - double elapsed; - - ASSERT(timer!=NULL); - - elapsed = timer->elapsed_real; - if (timer->running) elapsed += now_real() - timer->start_real; - - if (elapsed < 0.0) elapsed = 0.0; - - return elapsed; -} - - -void my_dequote(char *out, const char *in, const char *special){ - const char *p; - char *q; - char c; - p=in; - q=out; - while((c=*(p++))){ - if(c=='\\' && strchr(special,*p)){ - *(q++)=*(p++); - }else{ - *(q++)=c; - } - } - *q='\0'; -} - -void my_quote(char *out, const char *in, const char *special){ - const char *p; - char *q; - char c; - p=in; - q=out; - while(q-out< StringSize-2 && (c=*(p++))){ - if(c=='\\'){ - if(*p!=0 && strchr(special,*p)){ - *(q++)='\\'; - } - }else if(strchr(special,c)){ - *(q++)='\\'; - } - *(q++)=c; - } - *q='\0'; -} - - -void my_sleep(int msec){ -#ifndef _WIN32 - struct timespec tm; - tm.tv_sec=msec/1000; - tm.tv_nsec=1000000*(msec%1000); - nanosleep(&tm,NULL); -#else - Sleep(msec); -#endif -} + +// util.c + +// includes + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif + +#include "main.h" +#include "util.h" +#include "gui.h" + +// macros + +#define StringSize 4096 + +// variables + +static bool Error; + +FILE * LogFile=NULL; + +// functions + +// util_init() + +void util_init() { + + Error = FALSE; + + // init log file + + LogFile = NULL; + + // switch file buffering off + + setbuf(stdin,NULL); + setbuf(stdout,NULL); +} + +// my_random_init() + +void my_random_init() { + srand(time(NULL)); +} + +// my_random_int() + +int my_random_int(int n) { + + int r; + + ASSERT(n>0); + + r = ((int)floor(my_random_double()*((double)n))); + ASSERT(r>=0&&r=0.0&&r<1.0); + + return r; +} + +// my_atoll() + +sint64 my_atoll(const char string[]) { + + sint64 n; + + sscanf(string,S64_FORMAT,&n); + + return n; +} + +// my_round() + +int my_round(double x) { + + return ((int)floor(x+0.5)); +} + +// my_malloc() + +void * my_malloc(size_t size) { + + void * address; + + ASSERT(size>0); + + address = malloc(size); + if (address == NULL) my_fatal("my_malloc(): malloc(): %s\n",strerror(errno)); + + return address; +} + +// my_realloc() + +void * my_realloc(void * address, size_t size) { + + ASSERT(address!=NULL); + ASSERT(size>0); + + address = realloc(address,size); + if (address == NULL) my_fatal("my_realloc(): realloc(): %s\n",strerror(errno)); + + return address; +} + +// my_free() + +void my_free(void * address) { + + ASSERT(address!=NULL); + + free(address); +} + +// my_log_open() + +void my_log_open(const char file_name[]) { + + ASSERT(file_name!=NULL); + + LogFile = fopen(file_name,"a"); +#ifndef _WIN32 +//line buffering doesn't work too well in MSVC and/or windows + if (LogFile != NULL) setvbuf(LogFile,NULL,_IOLBF,0); // line buffering +#endif + if(LogFile!=NULL){ + my_log("POLYGLOT *** LOGFILE OPENED ***\n"); + } + +} + +// my_log_close() + +void my_log_close() { + + if (LogFile != NULL) fclose(LogFile); + LogFile=NULL; +} + +// my_log() + +void my_log(const char format[], ...) { + + char string[FormatBufferSize]; + + ASSERT(format!=NULL); + +// format + + CONSTRUCT_ARG_STRING(format,string); + + + if (LogFile != NULL) { + fprintf(LogFile,"%.3f %s",now_real(),string); +#ifdef _WIN32 + fflush(LogFile); +#endif + } +} + +// my_fatal() + +void my_fatal(const char format[], ...) { + + char string[FormatBufferSize]; + + ASSERT(format!=NULL); + +// format + + CONSTRUCT_ARG_STRING(format,string); + + my_log("POLYGLOT %s",string); + // This should be gui_send but this does not work. + // Why? + + printf("tellusererror POLYGLOT: %s",string); + + if (Error) { // recursive error + my_log("POLYGLOT *** RECURSIVE ERROR ***\n"); + exit(EXIT_FAILURE); + // abort(); + } else { + Error = TRUE; + quit(); + } +} + +// my_file_read_line() + +bool my_file_read_line(FILE * file, char string[], int size) { + + int src, dst; + int c; + + ASSERT(file!=NULL); + ASSERT(string!=NULL); + ASSERT(size>0); + + if (fgets(string,size,file) == NULL) { + if (feof(file)) { + return FALSE; + } else { // error + my_fatal("my_file_read_line(): fgets(): %s\n",strerror(errno)); + } + } + + // remove CRs and LFs + + src = 0; + dst = 0; + + while ((c=string[src++]) != '\0') { + if (c != '\r' && c != '\n') string[dst++] = c; + } + + string[dst] = '\0'; + + return TRUE; +} + +// my_file_join() + +void my_path_join(char *join_path, const char *path, const char *file){ + char separator; +#ifdef _WIN32 + separator='\\'; +#else + separator='/'; +#endif + snprintf(join_path,StringSize,"%s%c%s",path,separator,file); + join_path[StringSize-1]='\0'; +} + +// my_mkdir() + +int my_mkdir(const char *path){ + int ret; +#ifdef _WIN32 + ret=_mkdir(path); +#else + ret=mkdir(path,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + return ret; +} + + +// my_string_empty() + +bool my_string_empty(const char string[]) { + + return string == NULL || string[0] == '\0'; +} + +// my_string_whitespace() + +bool my_string_whitespace(const char string[]){ + int pos=0; + while(string[pos]!='\0'){ + if(string[pos]!=' ' && string[pos]!='\t'){ + return FALSE; + } + pos++; + } + return TRUE; +} + +// my_string_equal() + +bool my_string_equal(const char string_1[], const char string_2[]) { + + ASSERT(string_1!=NULL); + ASSERT(string_2!=NULL); + + return strcmp(string_1,string_2) == 0; +} + +// my_string_case_equal() + +bool my_string_case_equal(const char string_1[], const char string_2[]) { + + int c1, c2; + + ASSERT(string_1!=NULL); + ASSERT(string_2!=NULL); + + while (TRUE) { + + c1 = *string_1++; + c2 = *string_2++; + + if (tolower(c1) != tolower(c2)) return FALSE; + if (c1 == '\0') return TRUE; + } + + return FALSE; +} + +// my_strtolower() + +void my_string_tolower(char *dst, const char *src){ + int c; + ASSERT(src!=NULL); + ASSERT(dst!=NULL); + while((c=*(src++))){ + *dst=tolower(c); + dst++; + } + *(dst++)='\0'; +} + +// my_string_case_contains() + +const char* my_string_case_contains(const char string_1[], const char string_2[]){ + + char tmp1[StringSize]; + char tmp2[StringSize]; + char *where; + + + ASSERT(string_1!=NULL); + ASSERT(string_2!=NULL); + + my_string_tolower(tmp1,string_1); + my_string_tolower(tmp2,string_2); + + where=strstr(tmp1,tmp2); + if(where){ + return string_1+(where-tmp1); + } + return NULL; + + +} + + +// my_strdup() + +char * my_strdup(const char string[]) { + + char * address; + + ASSERT(string!=NULL); + + // strdup() is not ANSI C + + address = (char *) my_malloc(strlen(string)+1); + strcpy(address,string); + + return address; +} + +// my_string_clear() + +void my_string_clear(const char * * variable) { + + ASSERT(variable!=NULL); + + if (*variable != NULL) { + my_free((void*)(*variable)); + *variable = NULL; + } +} + +// my_string_set() + +void my_string_set(const char * * variable, const char string[]) { + + ASSERT(variable!=NULL); + ASSERT(string!=NULL); + + if (*variable != NULL) my_free((void*)(*variable)); + *variable = my_strdup(string); +} + +// now_real() + +double now_real() { +#ifndef _WIN32 + struct timeval tv[1]; + struct timezone tz[1]; + + tz->tz_minuteswest = 0; + tz->tz_dsttime = 0; // DST_NONE not declared in linux + + if (gettimeofday(tv,tz) == -1) { + my_fatal("now_real(): gettimeofday(): %s\n",strerror(errno)); + } + + return tv->tv_sec + tv->tv_usec * 1E-6; +#else + struct _timeb timeptr; + _ftime(&timeptr); + return(timeptr.time+((double)timeptr.millitm)/1000.0); +// return (double) GetTickCount() / 1000.0; // we can do better here:-) +#endif +} + + +// my_timer_reset() + +void my_timer_reset(my_timer_t * timer) { + + ASSERT(timer!=NULL); + + timer->start_real = 0.0; + timer->elapsed_real = 0.0; + timer->running = FALSE; +} + +// my_timer_start() + +void my_timer_start(my_timer_t * timer) { +// timer->start_real = 0.0; + timer->elapsed_real = 0.0; +// timer->running = FALSE; + ASSERT(timer!=NULL); + + timer->running = TRUE; + timer->start_real = now_real(); +} + +// my_timer_stop() + +void my_timer_stop(my_timer_t * timer) { + + ASSERT(timer!=NULL); + + ASSERT(timer->running); + + timer->elapsed_real += now_real() - timer->start_real; + timer->start_real = 0.0; + timer->running = FALSE; +} + +// my_timer_elapsed_real() + +double my_timer_elapsed_real(const my_timer_t * timer) { + + double elapsed; + + ASSERT(timer!=NULL); + + elapsed = timer->elapsed_real; + if (timer->running) elapsed += now_real() - timer->start_real; + + if (elapsed < 0.0) elapsed = 0.0; + + return elapsed; +} + + +void my_dequote(char *out, const char *in, const char *special){ + const char *p; + char *q; + char c; + p=in; + q=out; + while((c=*(p++))){ + if(c=='\\' && strchr(special,*p)){ + *(q++)=*(p++); + }else{ + *(q++)=c; + } + } + *q='\0'; +} + +void my_quote(char *out, const char *in, const char *special){ + const char *p; + char *q; + char c; + p=in; + q=out; + while(q-out< StringSize-2 && (c=*(p++))){ + if(c=='\\'){ + if(*p!=0 && strchr(special,*p)){ + *(q++)='\\'; + } + }else if(strchr(special,c)){ + *(q++)='\\'; + } + *(q++)=c; + } + *q='\0'; +} + + +void my_sleep(int msec){ +#ifndef _WIN32 + struct timespec tm; + tm.tv_sec=msec/1000; + tm.tv_nsec=1000000*(msec%1000); + nanosleep(&tm,NULL); +#else + Sleep(msec); +#endif +} diff --git a/util.h b/util.h index 3855a82..c25ef4e 100644 --- a/util.h +++ b/util.h @@ -1,192 +1,193 @@ - -// util.h - -#ifndef UTIL_H -#define UTIL_H - -// includes - -#include -#include -#include -#include - -// defines - -#ifndef EXIT_SUCCES -#define EXIT_SUCCES 0 -#endif - -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif - -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif - - -#undef FALSE -#define FALSE 0 - -#undef TRUE -#define TRUE 1 - -#ifdef DEBUG -# undef DEBUG -# define DEBUG TRUE -#else -# define DEBUG FALSE -#endif - -#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) -# define S64_FORMAT "%I64d" -# define U64_FORMAT "%016I64X" -#else -# define S64_FORMAT "%lld" -# define U64_FORMAT "%016llX" -#endif - -// macros - -#ifdef _MSC_VER -# define S64(u) (u##i64) -# define U64(u) (u##ui64) -#else -# define S64(u) (u##LL) -# define U64(u) (u##ULL) -#endif - -#undef ASSERT -#if DEBUG -# define ASSERT(a) { if (!(a)) my_fatal("file \"%s\", line %d, assertion \"" #a "\" failed\n",__FILE__,__LINE__); } -#else -# define ASSERT(a) -#endif - -#ifdef _WIN32 -#define snprintf _snprintf -#endif - -#define FormatBufferSize 4096 - -#ifdef _MSC_VER -#define vsnprintf _vsnprintf -#endif - -#define CONSTRUCT_ARG_STRING(format,buf) \ - { \ - va_list arg_list; \ - int written; \ - va_start(arg_list,format); \ - written=vsnprintf(buf, \ - sizeof(buf), \ - format, \ - arg_list); \ - va_end(arg_list); \ - buf[sizeof(buf)-1]='\0'; \ - if(written>=sizeof(buf) || written<0){ \ - my_fatal("write_buffer overflow: file \"%s\", line %d\n", \ - __FILE__,__LINE__); \ - } \ - } \ - -#define TO_BOOL(string) ((my_string_case_equal(string,"false") || \ - my_string_equal(string,"0"))?FALSE:TRUE) - -#define IS_BOOL(string) (my_string_case_equal(string,"false")|| \ - my_string_case_equal(string,"true") || \ - my_string_case_equal(string,"1") || \ - my_string_case_equal(string,"0")) -// types - -typedef signed char sint8; -typedef unsigned char uint8; - -typedef signed short sint16; -typedef unsigned short uint16; - -typedef signed int sint32; -typedef unsigned int uint32; - -typedef int bool; - -#ifdef _MSC_VER - typedef signed __int64 sint64; - typedef unsigned __int64 uint64; -#else - typedef signed long long int sint64; - typedef unsigned long long int uint64; -#endif - -typedef struct { - double start_real; - double elapsed_real; - bool running; -} my_timer_t; - - -// functions - -extern void util_init (); - -extern void my_random_init (); -extern int my_random_int (int n); -extern double my_random_double (); - -extern sint64 my_atoll (const char string[]); - -extern int my_round (double x); - -extern void * my_malloc (size_t size); -extern void * my_realloc (void * address, size_t size); -extern void my_free (void * address); - -extern void my_log_open (const char file_name[]); -extern void my_log_close (); - -extern void my_log (const char format[], ...); -extern void my_fatal (const char format[], ...); - -extern bool my_file_read_line (FILE * file, char string[], int size); -extern void my_path_join (char *join_path, const char *path, const char *file); - -extern int my_mkdir (const char *path); - -extern bool my_string_empty (const char string[]); -extern bool my_string_whitespace (const char string[]); -extern bool my_string_equal (const char string_1[], const char string_2[]); -extern bool my_string_case_equal (const char string_1[], const char string_2[]); -extern const char* my_string_case_contains(const char haystack[], - const char needle[]); - - -extern bool my_string_to_lower (char dst[], const char src[]); - -extern char * my_strdup (const char string[]); - -extern void my_string_clear (const char * * variable); -extern void my_string_set (const char * * variable, const char string[]); - -extern double now_real (); - -extern void my_timer_reset (my_timer_t * timer); -extern void my_timer_start (my_timer_t * timer); -extern void my_timer_stop (my_timer_t * timer); - -extern double my_timer_elapsed_real (const my_timer_t * timer); - -extern char * my_error(); - -extern void my_dequote (char *out, - const char *in, - const char *special); -extern void my_quote (char *out, - const char *in, - const char *special); - -extern void my_sleep (int msec); - -#endif // !defined UTIL_H - -// end of util.h + +// util.h + +#ifndef UTIL_H +#define UTIL_H + +// includes + +#include +#include +#include +#include + +// defines + +#ifndef EXIT_SUCCES +#define EXIT_SUCCES 0 +#endif + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + + +#undef FALSE +#define FALSE 0 + +#undef TRUE +#define TRUE 1 + +#ifdef DEBUG +# undef DEBUG +# define DEBUG TRUE +#else +# define DEBUG FALSE +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) +# define S64_FORMAT "%I64d" +# define U64_FORMAT "%016I64X" +#else +# define S64_FORMAT "%lld" +# define U64_FORMAT "%016llX" +#endif + +// macros + +#ifdef _MSC_VER +# define S64(u) (u##i64) +# define U64(u) (u##ui64) +#else +# define S64(u) (u##LL) +# define U64(u) (u##ULL) +#endif + +#undef ASSERT +#if DEBUG +# define ASSERT(a) { if (!(a)) my_fatal("file \"%s\", line %d, assertion \"" #a "\" failed\n",__FILE__,__LINE__); } +#else +# define ASSERT(a) +#endif + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +#define FormatBufferSize 4096 +#define StringSize 4096 + +#ifdef _MSC_VER +#define vsnprintf _vsnprintf +#endif + +#define CONSTRUCT_ARG_STRING(format,buf) \ + { \ + va_list arg_list; \ + int written; \ + va_start(arg_list,format); \ + written=vsnprintf(buf, \ + sizeof(buf), \ + format, \ + arg_list); \ + va_end(arg_list); \ + buf[sizeof(buf)-1]='\0'; \ + if(written>=sizeof(buf) || written<0){ \ + my_fatal("write_buffer overflow: file \"%s\", line %d\n", \ + __FILE__,__LINE__); \ + } \ + } \ + +#define TO_BOOL(string) ((my_string_case_equal(string,"false") || \ + my_string_equal(string,"0"))?FALSE:TRUE) + +#define IS_BOOL(string) (my_string_case_equal(string,"false")|| \ + my_string_case_equal(string,"true") || \ + my_string_case_equal(string,"1") || \ + my_string_case_equal(string,"0")) +// types + +typedef signed char sint8; +typedef unsigned char uint8; + +typedef signed short sint16; +typedef unsigned short uint16; + +typedef signed int sint32; +typedef unsigned int uint32; + +typedef int bool; + +#ifdef _MSC_VER + typedef signed __int64 sint64; + typedef unsigned __int64 uint64; +#else + typedef signed long long int sint64; + typedef unsigned long long int uint64; +#endif + +typedef struct { + double start_real; + double elapsed_real; + bool running; +} my_timer_t; + + +// functions + +extern void util_init (); + +extern void my_random_init (); +extern int my_random_int (int n); +extern double my_random_double (); + +extern sint64 my_atoll (const char string[]); + +extern int my_round (double x); + +extern void * my_malloc (size_t size); +extern void * my_realloc (void * address, size_t size); +extern void my_free (void * address); + +extern void my_log_open (const char file_name[]); +extern void my_log_close (); + +extern void my_log (const char format[], ...); +extern void my_fatal (const char format[], ...); + +extern bool my_file_read_line (FILE * file, char string[], int size); +extern void my_path_join (char *join_path, const char *path, const char *file); + +extern int my_mkdir (const char *path); + +extern bool my_string_empty (const char string[]); +extern bool my_string_whitespace (const char string[]); +extern bool my_string_equal (const char string_1[], const char string_2[]); +extern bool my_string_case_equal (const char string_1[], const char string_2[]); +extern const char* my_string_case_contains(const char haystack[], + const char needle[]); + + +extern bool my_string_to_lower (char dst[], const char src[]); + +extern char * my_strdup (const char string[]); + +extern void my_string_clear (const char * * variable); +extern void my_string_set (const char * * variable, const char string[]); + +extern double now_real (); + +extern void my_timer_reset (my_timer_t * timer); +extern void my_timer_start (my_timer_t * timer); +extern void my_timer_stop (my_timer_t * timer); + +extern double my_timer_elapsed_real (const my_timer_t * timer); + +extern char * my_error(); + +extern void my_dequote (char *out, + const char *in, + const char *special); +extern void my_quote (char *out, + const char *in, + const char *special); + +extern void my_sleep (int msec); + +#endif // !defined UTIL_H + +// end of util.h diff --git a/xboard2uci.c b/xboard2uci.c index 80e0a62..fe0ded3 100644 --- a/xboard2uci.c +++ b/xboard2uci.c @@ -1,1695 +1,1732 @@ - -// xboard2uci.c - -// includes - -#include -#include -#include -#include -#include - -#include "board.h" -#include "book.h" -#include "colour.h" -#include "engine.h" -#include "fen.h" -#include "game.h" -#include "gui.h" -#include "line.h" -#include "main.h" -#include "move.h" -#include "move_do.h" -#include "move_legal.h" -#include "option.h" -#include "parse.h" -#include "san.h" -#include "uci.h" -#include "uci2uci.h" -#include "util.h" -#include "xboard2uci.h" - -// defines - -#define StringSize 4096 - -// constants - -static const bool UseDebug = FALSE; -static const bool DelayPong = FALSE; - -// types - -typedef struct { - int state; - bool computer[ColourNb]; - int exp_move; - int resign_nb; - my_timer_t timer[1]; -} state_t; - -typedef struct { - bool has_feature_memory; - bool has_feature_smp; - bool has_feature_egt; - bool analyse; - bool computer; - const char * name; - bool ics; - bool new_hack; // "new" is a C++ keyword - bool ponder; - int ping; - bool post; - int proto_ver; - bool result; - - int mps; - double base; - double inc; - - bool time_limit; - double time_max; - - bool depth_limit; - int depth_max; - - double my_time; - double opp_time; - - int node_rate; -} xb_t; - -typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t; - -// variables - -static state_t State[1]; -static xb_t XB[1]; - -// prototypes - -static void comp_move (int move); -static void move_step (int move); -static void board_update (); - -static void mess (); -static void no_mess (int move); - -static void search_update (); -static void search_clear (); -static void update_remaining_time(); -static int report_best_score(); -static bool kibitz_throttle (bool searching); -static void start_protected_command(); -static void end_protected_command(); - -static bool active (); -static bool ponder (); -static bool ponder_ok (int ponder_move); - -static void stop_search (); - -static void send_board (int extra_move); -static void send_pv (); -static void send_info (); - -static void send_xboard_options (); - -static void learn (int result); - - -// functions - -// xboard2uci_init() - -void xboard2uci_init() { - // init - - game_clear(Game); - - // state - - State->state = WAIT; - - State->computer[White] = FALSE; - State->computer[Black] = TRUE; - - State->exp_move = MoveNone; - State->resign_nb = 0; - my_timer_reset(State->timer); - - // yes there are engines that do not have the "Hash" option.... - XB->has_feature_memory= (option_find(Uci->option,"Hash")!=NULL); - XB->has_feature_smp = (uci_thread_option(Uci)!=NULL); - // TODO: support for other types of table bases - XB->has_feature_egt = (option_find(Uci->option,"NalimovPath")!=NULL); - XB->analyse = FALSE; - XB->computer = FALSE; - XB->name = NULL; - my_string_set(&XB->name,""); - XB->ics = FALSE; - XB->new_hack = TRUE; - XB->ping = -1; - XB->ponder = FALSE; - XB->post = FALSE; - XB->proto_ver = 1; - XB->result = FALSE; - - XB->mps = 0; - XB->base = 300.0; - XB->inc = 0.0; - - XB->time_limit = FALSE; - XB->time_max = 5.0; - - XB->depth_limit = FALSE; - XB->depth_max = 127; - - XB->my_time = 300.0; - XB->opp_time = 300.0; - - XB->node_rate = -1; -} - -// xboard2uci_gui_step() - -void xboard2uci_gui_step(char string[]) { - - int move; - char move_string[256]; - board_t board[1]; - - if (FALSE) { - - } else if (match(string,"accepted *")) { - - // ignore - - } else if (match(string,"analyze")) { - - State->computer[White] = FALSE; - State->computer[Black] = FALSE; - - XB->analyse = TRUE; - XB->new_hack = FALSE; - ASSERT(!XB->result); - XB->result = FALSE; - - mess(); - - } else if (match(string,"bk")) { - - if (option_get_bool(Option,"Book")) { - game_get_board(Game,board); - book_disp(board); - } - - } else if (match(string,"black")) { - - if (colour_is_black(game_turn(Game))) { - - State->computer[White] = TRUE; - State->computer[Black] = FALSE; - - XB->new_hack = TRUE; - XB->result = FALSE; - - mess(); - } - - } else if (match(string,"computer")) { - - XB->computer = TRUE; - - } else if (match(string,"draw")) { - if(option_find(Uci->option,"UCI_DrawOffers")){ - my_log("POLYGLOT draw from XB received"); - uci_send_option(Uci,"DrawOffer","%s","draw");} - } else if (match(string,"easy")) { - - XB->ponder = FALSE; - - mess(); - - } else if (match(string,"edit")) { - - // refuse - - gui_send(GUI,"Error (unknown command): %s",string); - - } else if (match(string,"exit")) { - - State->computer[White] = FALSE; - State->computer[Black] = FALSE; - - XB->analyse = FALSE; - - mess(); - - } else if (match(string,"force")) { - - State->computer[White] = FALSE; - State->computer[Black] = FALSE; - - mess(); - - } else if (match(string,"go")) { - - State->computer[game_turn(Game)] = TRUE; - State->computer[colour_opp(game_turn(Game))] = FALSE; - - XB->new_hack = FALSE; - ASSERT(!XB->result); - XB->result = FALSE; - - mess(); - - } else if (match(string,"hard")) { - - XB->ponder = TRUE; - - mess(); - - } else if (match(string,"hint")) { - - if (option_get_bool(Option,"Book")) { - - game_get_board(Game,board); - move = book_move(board,FALSE); - - if (move != MoveNone && move_is_legal(move,board)) { - move_to_san(move,board,move_string,256); - gui_send(GUI,"Hint: %s",move_string); - } - } - - } else if (match(string,"ics *")) { - - XB->ics = TRUE; - - } else if (match(string,"level * *:* *")) { - - XB->mps = atoi(Star[0]); - XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2])); - XB->inc = ((double)atoi(Star[3])); - - } else if (match(string,"level * * *")) { - - XB->mps = atoi(Star[0]); - XB->base = ((double)atoi(Star[1])) * 60.0; - XB->inc = ((double)atoi(Star[2])); - - } else if (match(string,"name *")) { - - my_string_set(&XB->name,Star[0]); - - } else if (match(string,"new")) { - - uci_send_isready_sync(Uci); - my_log("POLYGLOT NEW GAME\n"); - - option_set(Option,"Chess960","false"); - - game_clear(Game); - - if (XB->analyse) { - State->computer[White] = FALSE; - State->computer[Black] = FALSE; - } else { - State->computer[White] = FALSE; - State->computer[Black] = TRUE; - } - - XB->new_hack = TRUE; - XB->result = FALSE; - - XB->depth_limit = FALSE; - XB->node_rate=-1; - - XB->computer = FALSE; - my_string_set(&XB->name,""); - - board_update(); - mess(); - - uci_send_ucinewgame(Uci); - - } else if (match(string,"nopost")) { - - XB->post = FALSE; - - } else if (match(string,"otim *")) { - - XB->opp_time = ((double)atoi(Star[0])) / 100.0; - if (XB->opp_time < 0.0) XB->opp_time = 0.0; - - } else if (match(string,"pause")) { - - // refuse - - gui_send(GUI,"Error (unknown command): %s",string); - - } else if (match(string,"ping *")) { - - // HACK; TODO: answer only after an engine move - - if (DelayPong) { - if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping - XB->ping = atoi(Star[0]); - uci_send_isready_sync(Uci); - } else { - ASSERT(XB->ping==-1); - gui_send(GUI,"pong %s",Star[0]); - } - } else if (match(string,"nps *")) { - - // fake WB play-by-nodes mode - XB->node_rate = atoi(Star[0]); - } else if (match(string,"playother")) { - - State->computer[game_turn(Game)] = FALSE; - State->computer[colour_opp(game_turn(Game))] = TRUE; - - XB->new_hack = FALSE; - ASSERT(!XB->result); - XB->result = FALSE; - - mess(); - - } else if (match(string,"post")) { - - XB->post = TRUE; - - } else if (match(string,"protover *")) { - XB->proto_ver = atoi(Star[0]); - ASSERT(XB->proto_ver>=2); - send_xboard_options(); - - } else if (match(string,"quit")) { - my_log("POLYGLOT *** \"quit\" from GUI ***\n"); - quit(); - } else if (match(string,"random")) { - - // ignore - - } else if (match(string,"rating * *")) { - - // ignore - - } else if (match(string,"remove")) { - - if (game_pos(Game) >= 2) { - - game_goto(Game,game_pos(Game)-2); - - ASSERT(!XB->new_hack); - XB->new_hack = FALSE; // HACK? - XB->result = FALSE; - - board_update(); - mess(); - } - - } else if (match(string,"rejected *")) { - - // ignore - - } else if (match(string,"reset")) { // protover 3? - - // refuse - - gui_send(GUI,"Error (unknown command): %s",string); - - } else if (FALSE - || match(string,"result * {*}") - || match(string,"result * {* }") - || match(string,"result * { *}") - || match(string,"result * { * }")) { - - my_log("POLYGLOT GAME END\n"); - - XB->result = TRUE; - - mess(); - - // book learning - - if (option_get_bool(Option,"Book") && - option_get_bool(Option,"BookLearn")) { - - if (FALSE) { - } else if (my_string_equal(Star[0],"1-0")) { - learn(+1); - } else if (my_string_equal(Star[0],"0-1")) { - learn(-1); - } else if (my_string_equal(Star[0],"1/2-1/2")) { - learn(0); - } - } - } else if (match(string,"resume")) { - - // refuse - - gui_send(GUI,"Error (unknown command): %s",string); - - } else if (match(string,"option *=*") || - match(string,"option * =*") || - match(string,"option *= *") || - match(string,"option * = *") - ){ - char *name=Star[0]; - char *value=Star[1]; - if(match(name, "Polyglot *")){ - char *pg_name=Star[0]; - polyglot_set_option(pg_name,value); - }else{ - option_t *opt=option_find(Uci->option,name); - if(opt){ - if(my_string_case_equal(opt->type,"check")){ - value=my_string_equal(value,"1")?"true":"false"; - } - start_protected_command(); - uci_send_option(Uci, name, "%s", value); - end_protected_command(); - }else{ - gui_send(GUI,"Error (unknown option): %s",name); - } - } - } else if (match(string,"option *")){ - char *name=Star[0]; - if(match(name, "Polyglot *")){ - char *pg_name=Star[0]; - polyglot_set_option(pg_name,""); - }else{ - start_protected_command(); - // value is ignored - if(!uci_send_option(Uci, name, "%s", "")){ - gui_send(GUI,"Error (unknown option): %s",name); - }; - end_protected_command(); - } - } else if (XB->has_feature_smp && match(string,"cores *")){ - int cores=atoi(Star[0]); - if(cores>=1){ - // updating the number of cores - my_log("POLYGLOT setting the number of cores to %d\n",cores); - start_protected_command(); - uci_set_threads(Uci,cores); - end_protected_command(); - } else{ - // refuse - gui_send(GUI,"Error (unknown command): %s",string); - } - } else if (XB->has_feature_egt && match(string,"egtpath * *")){ - char *type=Star[0]; - char *path=Star[1]; - if(!my_string_case_equal(type,"nalimov")){ - // refuse - gui_send(GUI,"Error (unsupported table base format): %s",string); - }else if(my_string_empty(path)){ - // refuse - gui_send(GUI,"Error (unknown command): %s",string); - }else{ - // updating NalimovPath - my_log("POLYGLOT setting the Nalimov path to %s\n",path); - start_protected_command(); - uci_send_option(Uci,"NalimovPath","%s",path); - end_protected_command(); - } - } else if (XB->has_feature_memory && match(string,"memory *")){ - int memory = atoi(Star[0]); - int nalimov_cache; - int real_memory; - if(memory>=1){ - // updating the available memory - option_t *opt; - my_log("POLYGLOT setting the amount of memory to %dMb\n",memory); - if((opt=option_find(Uci->option,"NalimovCache"))){ - nalimov_cache=atoi(opt->value); - }else{ - nalimov_cache=0; - } - my_log("POLYGLOT Nalimov Cache is %dMb\n",nalimov_cache); - real_memory=memory-nalimov_cache; - if(real_memory>0){ - start_protected_command(); - uci_send_option(Uci,"Hash", "%d", real_memory); - end_protected_command(); - } - }else{ - // refuse - gui_send(GUI,"Error (unknown command): %s",string); - } - - } else if (match(string,"sd *")) { - - XB->depth_limit = TRUE; - XB->depth_max = atoi(Star[0]); - - } else if (match(string,"setboard *")) { - - my_log("POLYGLOT FEN %s\n",Star[0]); - - if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]); - - State->computer[White] = FALSE; - State->computer[Black] = FALSE; - - XB->new_hack = TRUE; // HACK? - XB->result = FALSE; - - board_update(); - mess(); - - } else if (match(string,"st *")) { - - XB->time_limit = TRUE; - XB->time_max = ((double)atoi(Star[0])); - - } else if (match(string,"time *")) { - - XB->my_time = ((double)atoi(Star[0])) / 100.0; - if (XB->my_time < 0.0) XB->my_time = 0.0; - - } else if (match(string,"undo")) { - - if (game_pos(Game) >= 1) { - - game_goto(Game,game_pos(Game)-1); - - ASSERT(!XB->new_hack); - XB->new_hack = FALSE; // HACK? - XB->result = FALSE; - - board_update(); - mess(); - } - - } else if (match(string,"usermove *")) { - - game_get_board(Game,board); - move = move_from_san(Star[0],board); - - if (move != MoveNone && move_is_legal(move,board)) { - - XB->new_hack = FALSE; - ASSERT(!XB->result); - XB->result = FALSE; - - move_step(move); - no_mess(move); - - } else { - - gui_send(GUI,"Illegal move: %s",Star[0]); - } - - } else if (match(string,"variant *")) { - - if (my_string_equal(Star[0],"fischerandom")) { - option_set(Option,"Chess960","true"); - } else { - option_set(Option,"Chess960","false"); - } - - } else if (match(string,"white")) { - - if (colour_is_white(game_turn(Game))) { - - State->computer[White] = FALSE; - State->computer[Black] = TRUE; - - XB->new_hack = TRUE; - XB->result = FALSE; - - mess(); - } - - } else if (match(string,"xboard")) { - - // ignore - - } else if (match(string,".")) { // analyse info - - if (State->state == ANALYSE) { - int depth=Uci->best_depth;//HACK: don't clear engine-output window... - - ASSERT(Uci->searching); - ASSERT(Uci->pending_nb>=1); - - if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) { - move_to_san(Uci->root_move,Uci->board,move_string,256); - gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d %s",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,Uci->root_move_nb-(Uci->root_move_pos+1),Uci->root_move_nb,move_string); - } else { - gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK - } - } - - } else if (match(string,"?")) { // move now - - if (State->state == THINK) { - - ASSERT(Uci->searching); - ASSERT(Uci->pending_nb>=1); - - // HACK: just send "stop" to the engine - - if (Uci->searching) { - my_log("POLYGLOT STOP SEARCH\n"); - engine_send(Engine,"stop"); - } - } - - } else { // unknown command, maybe a move? - - game_get_board(Game,board); - move = move_from_san(string,board); - - if (move != MoveNone && move_is_legal(move,board)) { - - XB->new_hack = FALSE; - ASSERT(!XB->result); - XB->result = FALSE; - - move_step(move); - no_mess(move); - - } else if (move != MoveNone) { - - gui_send(GUI,"Illegal move: %s",string); - - } else { - - gui_send(GUI,"Error (unknown command): %s",string); - } - } - return; -} - -// xboard2uci_engine_step() - -void xboard2uci_engine_step(char string[]) { - - int event; - board_t board[1]; - event = uci_parse(Uci,string); - - // react to events - - if ((event & EVENT_READY) != 0) { - - // the engine is now ready - - if (!Uci->ready) { - Uci->ready = TRUE; - // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1"); - } - - if (!DelayPong && XB->ping >= 0) { - gui_send(GUI,"pong %d",XB->ping); - XB->ping = -1; - } - } - - if ((event & EVENT_MOVE) != 0 && State->state == THINK) { - - // the engine is playing a move - - // MEGA HACK: estimate remaining time because XBoard won't send it! - - my_timer_stop(State->timer); - - XB->my_time -= my_timer_elapsed_real(State->timer); - XB->my_time += XB->inc; - if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base; - - if (XB->my_time < 0.0) XB->my_time = 0.0; - - // play the engine move - - comp_move(Uci->best_move); - } - - if ((event & EVENT_PV) != 0) { - - // the engine has sent a new PV - - send_pv(); - } - if ((event & EVENT_INFO) != 0) { - - // the engine has sent info - - send_info(); - } - if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){ - my_log("POYGLOT draw offer/resign from engine\n"); - if(option_find(Uci->option,"UCI_DrawOffers")){ - if(event & EVENT_DRAW) - gui_send(GUI,"offer draw"); - else - gui_send(GUI,"resign"); - } - } - if(((event & EVENT_ILLEGAL_MOVE)!=0) && (State->state == THINK)){ - game_get_board(Game,board); - if(board->turn==White){ - gui_send(GUI,"0-1 {polyglot: resign" - " (illegal engine move by white: %s)}",Uci->bestmove); - }else{ - gui_send(GUI,"1-0 {polyglot: resign" - " (illegal engine move by black: %s)}",Uci->bestmove); - } - board_disp(board); - XB->result = TRUE; - mess(); - } -} - -// format_xboard_option_line - -void format_xboard_option_line(char * option_line, option_t *opt){ - int j; - char option_string[StringSize]; - char *tmp; - strcpy(option_line,""); - // buffer overflow alert - strcat(option_line,"feature option=\""); - if(opt->mode&PG){ - strcat(option_line,"Polyglot "); - } - sprintf(option_string,"%s",opt->name); - strcat(option_line,option_string); - sprintf(option_string," -%s",opt->type); - strcat(option_line,option_string); - if(!IS_BUTTON(opt->type) && strcmp(opt->type,"combo")){ - if(strcmp(opt->type,"check")){ - sprintf(option_string," %s",opt->value); - }else{ - sprintf(option_string," %d", - my_string_case_equal(opt->value,"true")|| - my_string_equal(opt->value,"1") - ?1:0); - } - strcat(option_line,option_string); - } - if(IS_SPIN(opt->type)){ - sprintf(option_string," %s",opt->min); - strcat(option_line,option_string); - } - if(IS_SPIN(opt->type)){ - sprintf(option_string," %s",opt->max); - strcat(option_line,option_string); - } - for(j=0;jvar_nb;j++){ - if(!strcmp(opt->var[j],opt->value)){ - sprintf(option_string," *%s",opt->var[j]); - }else{ - sprintf(option_string," %s",opt->var[j]); - } - strcat(option_line,option_string); - if(j!=opt->var_nb-1){ - strcat(option_line," ///"); - } - } - strcat(option_line,"\""); - if(option_get_bool(Option,"WbWorkArounds") && - (tmp=strstr(option_line,"Draw"))){ - *tmp='d'; - my_log("POLYGLOT Decapitalizing \"Draw\" in option \"%s\"\n", - opt->name); - } -} - -// send_xboard_options() - -static void send_xboard_options(){ - - - gui_send(GUI,"feature done=0"); - - gui_send(GUI,"feature analyze=1"); - gui_send(GUI,"feature colors=0"); - gui_send(GUI,"feature draw=1"); - gui_send(GUI,"feature ics=1"); - gui_send(GUI,"feature myname=\"%s\"", - option_get_string(Option,"EngineName")); - gui_send(GUI,"feature name=1"); - gui_send(GUI,"feature pause=0"); - gui_send(GUI,"feature ping=1"); - gui_send(GUI,"feature playother=1"); - gui_send(GUI,"feature sigint=1"); - gui_send(GUI,"feature reuse=1"); - gui_send(GUI,"feature san=0"); - gui_send(GUI,"feature setboard=1"); - gui_send(GUI,"feature sigint=0"); - gui_send(GUI,"feature sigterm=0"); - gui_send(GUI,"feature time=1"); - gui_send(GUI,"feature usermove=1"); - gui_send(GUI,"feature nps=1"); - if (XB->has_feature_memory){ - gui_send(GUI,"feature memory=1"); - }else{ - gui_send(GUI,"feature memory=0"); - } - if (XB->has_feature_smp){ - gui_send(GUI,"feature smp=1"); - }else{ - gui_send(GUI,"feature smp=0"); - } - if (XB->has_feature_egt){ - // TODO: support for other types of table bases - gui_send(GUI,"feature egt=\"nalimov\""); - }else{ - gui_send(GUI,"feature egt=\"\""); - } - - if (option_find(Uci->option,"UCI_Chess960")) { - gui_send(GUI,"feature variants=\"normal,fischerandom\""); - } else { - gui_send(GUI,"feature variants=\"normal\""); - } - - xboard2uci_send_options(); -} - -void xboard2uci_send_options(){ - char option_line[StringSize]=""; - const char * name; - option_t *opt; - - option_start_iter(Uci->option); - while((opt=option_next(Uci->option))){ - if(my_string_case_equal(opt->name,"UCI_AnalyseMode")) continue; - if(my_string_case_equal(opt->name,"UCI_Opponent")) continue; - if(my_string_case_equal(opt->name,"UCI_Chess960")) continue; - if(my_string_case_equal(opt->name,"UCI_ShowCurrLine")) continue; - if(my_string_case_equal(opt->name,"UCI_ShowRefutations")) continue; - if(my_string_case_equal(opt->name,"UCI_ShredderbasesPath")) continue; - if(my_string_case_equal(opt->name,"UCI_SetPositionValue")) continue; - if(my_string_case_equal(opt->name,"UCI_DrawOffers")) continue; - if(my_string_case_equal(opt->name,"Ponder")) continue; - if(my_string_case_equal(opt->name,"Hash")) continue; - if(my_string_case_equal(opt->name,"NalimovPath")) continue; - if((name=uci_thread_option(Uci))!=NULL && - my_string_case_equal(opt->name,name)) continue; - format_xboard_option_line(option_line,opt); - - gui_send(GUI,"%s",option_line); - } - - - option_start_iter(Option); - while((opt=option_next(Option))){ - if(opt->mode &XBOARD){ - format_xboard_option_line(option_line,opt); - gui_send(GUI,"%s",option_line); - } - } - gui_send(GUI,"feature done=1"); - -} - -// report_best_score() - -static int report_best_score(){ - if(!option_get_bool(Option,"ScoreWhite") || - colour_is_white(Uci->board->turn)){ - return Uci->best_score; - }else{ - return -Uci->best_score; - } -} - -// comp_move() - -static void comp_move(int move) { - - board_t board[1]; - char string[256]; - - ASSERT(move_is_ok(move)); - - ASSERT(State->state==THINK); - ASSERT(!XB->analyse); - - if(option_get_bool(Option,"RepeatPV")) - send_pv(); // to update time and nodes - - // send the move - - game_get_board(Game,board); - - if (move_is_castle(move,board) && option_get_bool(Option,"Chess960")) { - if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O - } else { - if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n"); - } - - gui_send(GUI,"move %s",string); - - // resign? - - if (option_get_bool(Option,"Resign") && Uci->root_move_nb > 1) { - - if (Uci->best_score <= -abs(option_get_int(Option,"ResignScore"))) { - - State->resign_nb++; - my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":""); - - if (State->resign_nb >= option_get_int(Option,"ResignMoves")) { - my_log("POLYGLOT *** RESIGN ***\n"); - gui_send(GUI,"resign"); - } - - } else { - - if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb); - State->resign_nb = 0; - } - } - - // play the move - - move_step(move); - no_mess(move); -} - -// move_step() - -static void move_step(int move) { - - board_t board[1]; - char move_string[256]; - - ASSERT(move_is_ok(move)); - - // log - - game_get_board(Game,board); - - if (move != MoveNone && move_is_legal(move,board)) { - - move_to_san(move,board,move_string,256); - my_log("POLYGLOT MOVE %s\n",move_string); - - } else { - - move_to_can(move,board,move_string,256); - my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string); - board_disp(board); - - my_fatal("move_step(): illegal move \"%s\"\n",move_string); - } - - // play the move - - game_add_move(Game,move); - board_update(); -} - -// board_update() - -static void board_update() { - - // handle game end - - ASSERT(!XB->result); - - switch (game_status(Game)) { - case PLAYING: - break; - case WHITE_MATES: - gui_send(GUI,"1-0 {White mates}"); - break; - case BLACK_MATES: - gui_send(GUI,"0-1 {Black mates}"); - break; - case STALEMATE: - gui_send(GUI,"1/2-1/2 {Stalemate}"); - break; - case DRAW_MATERIAL: - gui_send(GUI,"1/2-1/2 {Draw by insufficient material}"); - break; - case DRAW_FIFTY: - gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}"); - break; - case DRAW_REPETITION: - gui_send(GUI,"1/2-1/2 {Draw by repetition}"); - break; - default: - ASSERT(FALSE); - break; - } -} - -// mess() - -static void mess() { - - // clear state variables - - State->resign_nb = 0; - State->exp_move = MoveNone; - my_timer_reset(State->timer); - - // abort a possible search - - stop_search(); - - // calculate the new state - - if (FALSE) { - } else if (!active()) { - State->state = WAIT; - my_log("POLYGLOT WAIT\n"); - } else if (XB->analyse) { - State->state = ANALYSE; - my_log("POLYGLOT ANALYSE\n"); - } else if (State->computer[game_turn(Game)]) { - State->state = THINK; - my_log("POLYGLOT THINK\n"); - } else { - State->state = WAIT; - my_log("POLYGLOT WAIT\n"); - } - - search_update(); -} - -// no_mess() - -static void no_mess(int move) { - - ASSERT(move_is_ok(move)); - - // just received a move, calculate the new state - - if (FALSE) { - - } else if (!active()) { - - stop_search(); // abort a possible search - - State->state = WAIT; - State->exp_move = MoveNone; - - my_log("POLYGLOT WAIT\n"); - - } else if (State->state == WAIT) { - - ASSERT(State->computer[game_turn(Game)]); - ASSERT(!State->computer[colour_opp(game_turn(Game))]); - ASSERT(!XB->analyse); - - my_log("POLYGLOT WAIT -> THINK\n"); - - State->state = THINK; - State->exp_move = MoveNone; - - } else if (State->state == THINK) { - - ASSERT(!State->computer[game_turn(Game)]); - ASSERT(State->computer[colour_opp(game_turn(Game))]); - ASSERT(!XB->analyse); - - if (ponder() && ponder_ok(Uci->ponder_move)) { - - my_log("POLYGLOT THINK -> PONDER\n"); - - State->state = PONDER; - State->exp_move = Uci->ponder_move; - - } else { - - my_log("POLYGLOT THINK -> WAIT\n"); - - State->state = WAIT; - State->exp_move = MoveNone; - } - - } else if (State->state == PONDER) { - - ASSERT(State->computer[game_turn(Game)]); - ASSERT(!State->computer[colour_opp(game_turn(Game))]); - ASSERT(!XB->analyse); - - if (move == State->exp_move && Uci->searching) { - - ASSERT(Uci->searching); - ASSERT(Uci->pending_nb>=1); - - my_timer_start(State->timer);//also resets - - my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n"); - engine_send(Engine,"ponderhit"); - - State->state = THINK; - State->exp_move = MoveNone; - - send_pv(); // update display - - return; // do not launch a new search - - } else { - - my_log("POLYGLOT PONDER -> THINK (miss)\n"); - - stop_search(); - - State->state = THINK; - State->exp_move = MoveNone; - } - - } else if (State->state == ANALYSE) { - - ASSERT(XB->analyse); - - my_log("POLYGLOT ANALYSE -> ANALYSE\n"); - - stop_search(); - - } else { - - ASSERT(FALSE); - } - - search_update(); -} - -// start_protected_command() - -static void start_protected_command(){ - stop_search(); -} - -static void end_protected_command(){ - if(Uci->ready){ // not init faze - uci_send_isready_sync(Uci); // gobble up spurious "bestmove" - } - update_remaining_time(); - search_update(); // relaunch search if necessary -} - -// update_remaining_time() - -static void update_remaining_time(){ - double reduce; - if(State->timer->running){ - my_timer_stop(State->timer); - reduce = my_timer_elapsed_real(State->timer); - my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce); - XB->my_time -= reduce; - if(XB->my_time<0.0){ - XB->my_time=0.0; - } - } -} - - -// search_update() - -static void search_update() { - - int move; - int move_nb; - board_t board[1]; - - ASSERT(!Uci->searching); - - - - - // launch a new search if needed - - - - if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) { - - // [VdB] moved up as we need the move number - - game_get_board(Game,Uci->board); - - // opening book - - if (State->state == THINK && - option_get_bool(Option,"Book") && - Uci->board->move_nbboard,option_get_bool(Option,"BookRandom")); - - if (move != MoveNone && move_is_legal(move,Uci->board)) { - - my_log("POLYGLOT *BOOK MOVE*\n"); - - search_clear(); // clears Uci->ponder_move - Uci->best_move = move; - - board_copy(board,Uci->board); - move_do(board,move); - Uci->ponder_move = book_move(board,FALSE); // expected move = best book move - - Uci->best_pv[0] = Uci->best_move; - Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone - Uci->best_pv[2] = MoveNone; - - comp_move(Uci->best_move); - - return; - } - } - - // engine search - - my_log("POLYGLOT START SEARCH\n"); - - // options - - uci_send_option(Uci,"UCI_Chess960","%s", - option_get_bool(Option,"Chess960")?"true":"false"); - - if (option_get_int(Option,"UCIVersion") >= 2) { - uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name); - uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false"); - } - - uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false"); - - // position - - move = (State->state == PONDER) ? State->exp_move : MoveNone; - send_board(move); // updates Uci->board global variable - - // search - - if (State->state == THINK || State->state == PONDER) { - - engine_send_queue(Engine,"go"); - - if (XB->time_limit) { - - // fixed time per move - - if(XB->node_rate > 0){ - engine_send_queue(Engine, - " nodes %.0f", - XB->time_max*((double)XB->node_rate)); - }else{ - engine_send_queue(Engine, - " movetime %.0f", - XB->time_max*1000.0); - } - - } else { - - // time controls - - if(XB->node_rate > 0) { - double time; - move_nb = 40; - if (XB->mps != 0){ - move_nb = XB->mps - (Uci->board->move_nb % XB->mps); - } - time = XB->my_time / move_nb; - if(XB->inc != 0){ - time += XB->inc; - } - if(time > XB->my_time){ - time = XB->my_time; - } - engine_send_queue(Engine, - " nodes %.0f", - time*XB->node_rate); - } else { - - if (colour_is_white(Uci->board->turn)) { - engine_send_queue(Engine, - " wtime %.0f btime %.0f", - XB->my_time*1000.0,XB->opp_time*1000.0); - } else { - engine_send_queue(Engine, - " wtime %.0f btime %.0f", - XB->opp_time*1000.0,XB->my_time*1000.0); - } - - if (XB->inc != 0.0){ - engine_send_queue(Engine, - " winc %.0f binc %.0f", - XB->inc*1000.0,XB->inc*1000.0); - } - if (XB->mps != 0) { - - move_nb = XB->mps - (Uci->board->move_nb % XB->mps); - ASSERT(move_nb>=1&&move_nb<=XB->mps); - - engine_send_queue(Engine," movestogo %d",move_nb); - } - } - } - if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max); - - if (State->state == PONDER) engine_send_queue(Engine," ponder"); - - engine_send(Engine,""); // newline - - } else if (State->state == ANALYSE) { - - engine_send(Engine,"go infinite"); - - } else { - - ASSERT(FALSE); - } - - // init search info - - ASSERT(!Uci->searching); - - search_clear(); - - Uci->searching = TRUE; - Uci->pending_nb++; - } -} - -// search_clear() - -static void search_clear() { - - uci_clear(Uci); - - // TODO: MOVE ME - - my_timer_start(State->timer);//also resets -} - -// active() - -static bool active() { - - // position state - - if (game_status(Game) != PLAYING) return FALSE; // game ended - - // xboard state - - if (XB->analyse) return TRUE; // analysing - if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode - if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game - - return TRUE; // playing -} - -// ponder() - -static bool ponder() { - - return XB->ponder && (option_get_bool(Option,"CanPonder") || - option_find(Uci->option,"Ponder")); -} -// ponder_ok() - -static bool ponder_ok(int move) { - int status; - board_t board[1]; - - ASSERT(move==MoveNone||move_is_ok(move)); - - // legal ponder move? - - if (move == MoveNone) return FALSE; - - game_get_board(Game,board); - if (!move_is_legal(move,board)) return FALSE; - - // UCI-legal resulting position? - - game_add_move(Game,move); - - game_get_board(Game,board); - status = game_status(Game); - - game_rem_move(Game); - - if (status != PLAYING) return FALSE; // game ended - - if (option_get_bool(Option,"Book") && is_in_book(board)) { - return FALSE; - } - - return TRUE; -} - -// stop_search() - -static void stop_search() { - - if (Uci->searching) { - - ASSERT(Uci->searching); - ASSERT(Uci->pending_nb>=1); - - my_log("POLYGLOT STOP SEARCH\n"); - -/* - engine_send(Engine,"stop"); - Uci->searching = FALSE; -*/ - - if (option_get_bool(Option,"SyncStop")) { - uci_send_stop_sync(Uci); - } else { - uci_send_stop(Uci); - } - } -} - -// send_board() - -static void send_board(int extra_move) { - - char fen[256]; - int start, end; - board_t board[1]; - int pos; - int move; - char string[256]; - - ASSERT(extra_move==MoveNone||move_is_ok(extra_move)); - - ASSERT(!Uci->searching); - - // init - - game_get_board(Game,Uci->board); - if (extra_move != MoveNone) move_do(Uci->board,extra_move); - - board_to_fen(Uci->board,fen,256); - my_log("POLYGLOT FEN %s\n",fen); - - ASSERT(board_can_play(Uci->board)); - - // more init - - start = 0; - end = game_pos(Game); - ASSERT(end>=start); - - // position - - game_get_board_ex(Game,board,start); - board_to_fen(board,string,256); - - engine_send_queue(Engine,"position"); - - if (my_string_equal(string,StartFen)) { - engine_send_queue(Engine," startpos"); - } else { - engine_send_queue(Engine," fen %s",string); - } - - // move list - - if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves"); - - for (pos = start; pos < end; pos++) { // game moves - - move = game_move(Game,pos); - - move_to_can(move,board,string,256); - engine_send_queue(Engine," %s",string); - - move_do(board,move); - } - - if (extra_move != MoveNone) { // move to ponder on - move_to_can(extra_move,board,string,256); - engine_send_queue(Engine," %s",string); - } - - // end - - engine_send(Engine,""); // newline -} - -// send_info() - -static void send_info() { - int min_depth; - if(option_get_bool(Option,"WbWorkArounds2")){ - // Silly bug in some versions of WinBoard. - // depth <=1 clears the engine output window. - // Why shouldn't an engine be allowed to send info at depth 1? - min_depth=2; - }else{ - min_depth=1; - } - gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth>min_depth?Uci->best_depth:min_depth, - 0,0,0.0,0,Uci->info); -} - -// send_pv() - -static void send_pv() { - - char pv_string[StringSize]; - board_t board[1]; - int move; - char move_string[StringSize]; - - ASSERT(State->state!=WAIT); - - if (Uci->best_depth == 0) return; - - // xboard search information - - if (XB->post) { - - if (State->state == THINK || State->state == ANALYSE) { - - line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); - - if(Uci->depth==-1) //hack to clear the engine output window - gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb); - - gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string); - - } else if (State->state == PONDER && - option_get_bool(Option,"ShowPonder")) { - - game_get_board(Game,board); - move = State->exp_move; - - if (move != MoveNone && move_is_legal(move,board)) { - move_to_san(move,board,move_string,256); - line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); - gui_send(GUI,"%d %+d %.0f "S64_FORMAT" (%s) %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,move_string,pv_string); - } - } - } - - // kibitz - - if ((Uci->searching && - option_get_bool(Option,"KibitzPV") && - Uci->time >= option_get_double(Option,"KibitzDelay")) - || (!Uci->searching && option_get_bool(Option,"KibitzMove"))) { - - if (State->state == THINK || State->state == ANALYSE) { - - line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); - if(kibitz_throttle(Uci->searching)){ - gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"%s\"",option_get_string(Option,"KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,((double)report_best_score())/100.0,pv_string); - } - } else if (State->state == PONDER) { - - game_get_board(Game,board); - move = State->exp_move; - - if (move != MoveNone && move_is_legal(move,board)) { - move_to_san(move,board,move_string,256); - line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); - if(kibitz_throttle(Uci->searching)){ - gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string(Option,"KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,((double)report_best_score())/100.0,move_string,pv_string); - } - } - } - } -} - -// kibitz_throttle() - -static bool kibitz_throttle(bool searching){ - time_t curr_time; - static time_t lastKibitzMove=0; - static time_t lastKibitzPV=0; - curr_time = time(NULL); - if(searching){ // KibitzPV - if(curr_time >= - (option_get_int(Option,"KibitzInterval") + lastKibitzPV)){ - lastKibitzPV=curr_time; - return TRUE; - } - }else{ // KibitzMove - if(curr_time >= - (option_get_int(Option,"KibitzInterval") + lastKibitzMove)){ - lastKibitzPV=curr_time; - lastKibitzMove=curr_time; - return TRUE; - } - } - return FALSE; -} - -// learn() - -static void learn(int result) { - - int pos; - board_t board[1]; - int move; - - ASSERT(result>=-1&&result<=+1); - - ASSERT(XB->result); - ASSERT(State->computer[White]||State->computer[Black]); - - // init - - pos = 0; - - if (FALSE) { - } else if (State->computer[White]) { - pos = 0; - } else if (State->computer[Black]) { - pos = 1; - result = -result; - } else { - my_fatal("learn(): unknown side\n"); - } - - if (FALSE) { - } else if (result > 0) { - my_log("POLYGLOT *LEARN WIN*\n"); - } else if (result < 0) { - my_log("POLYGLOT *LEARN LOSS*\n"); - } else { - my_log("POLYGLOT *LEARN DRAW*\n"); - } - - // loop - - for (; pos < Game->size; pos += 2) { - - game_get_board_ex(Game,board,pos); - move = game_move(Game,pos); - - book_learn_move(board,move,result); - } - - book_flush(); -} - -// end of xboard2uci.c + +// xboard2uci.c + +// includes + +#include +#include +#include +#include +#include + +#include "board.h" +#include "book.h" +#include "colour.h" +#include "engine.h" +#include "fen.h" +#include "game.h" +#include "gui.h" +#include "line.h" +#include "main.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "uci.h" +#include "uci2uci.h" +#include "util.h" +#include "xboard2uci.h" + +// defines + +#define StringSize 4096 + +// constants + +static const bool UseDebug = FALSE; +static const bool DelayPong = FALSE; + +// types + +typedef struct { + int state; + bool computer[ColourNb]; + int exp_move; + int hint_move; + int resign_nb; + my_timer_t timer[1]; +} state_t; + +typedef struct { + bool has_feature_memory; + bool has_feature_smp; + bool has_feature_egt_nalimov; + bool has_feature_egt_gaviota; + bool analyse; + bool computer; + const char * name; + bool ics; + bool new_hack; // "new" is a C++ keyword + bool ponder; + int ping; + bool post; + int proto_ver; + bool result; + + int mps; + double base; + double inc; + + bool time_limit; + double time_max; + + bool depth_limit; + int depth_max; + + double my_time; + double opp_time; + + int node_rate; +} xb_t; + +typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t; + +// variables + +static state_t State[1]; +static xb_t XB[1]; + +// prototypes + +static void comp_move (int move); +static void move_step (int move); +static void board_update (); + +static void mess (); +static void no_mess (int move); + +static void search_update (); +static void search_clear (); +static void update_remaining_time(); +static int report_best_score(); +static bool kibitz_throttle (bool searching); +static void start_protected_command(); +static void end_protected_command(); + +static bool active (); +static bool ponder (); +static bool ponder_ok (int ponder_move); + +static void stop_search (); + +static void send_board (int extra_move); +static void send_pv (); +static void send_info (); + +static void send_xboard_options (); + +static void learn (int result); + + +// functions + +// xboard2uci_init() + +void xboard2uci_init() { + // init + + game_clear(Game); + + // state + + State->state = WAIT; + + State->computer[White] = FALSE; + State->computer[Black] = TRUE; + + State->exp_move = MoveNone; + State->hint_move = MoveNone; + State->resign_nb = 0; + my_timer_reset(State->timer); + + // yes there are engines that do not have the "Hash" option.... + XB->has_feature_memory= (option_find(Uci->option,"Hash")!=NULL); + XB->has_feature_smp = (uci_thread_option(Uci)!=NULL); + // TODO: support for other types of table bases + // This is a quick hack. + XB->has_feature_egt_nalimov = (option_find(Uci->option,"NalimovPath")!=NULL); + XB->has_feature_egt_gaviota = (option_find(Uci->option,"GaviotaTbPath")!=NULL); + XB->analyse = FALSE; + XB->computer = FALSE; + XB->name = NULL; + my_string_set(&XB->name,""); + XB->ics = FALSE; + XB->new_hack = TRUE; + XB->ping = -1; + XB->ponder = FALSE; + XB->post = FALSE; + XB->proto_ver = 1; + XB->result = FALSE; + + XB->mps = 0; + XB->base = 300.0; + XB->inc = 0.0; + + XB->time_limit = FALSE; + XB->time_max = 5.0; + + XB->depth_limit = FALSE; + XB->depth_max = 127; + + XB->my_time = 300.0; + XB->opp_time = 300.0; + + XB->node_rate = -1; +} + +// xboard2uci_gui_step() + +void xboard2uci_gui_step(char string[]) { + + int move; + char move_string[256]; + board_t board[1]; + + if (FALSE) { + + } else if (match(string,"accepted *")) { + + // ignore + + } else if (match(string,"analyze")) { + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + XB->analyse = TRUE; + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + mess(); + + } else if (match(string,"bk")) { + + if (option_get_bool(Option,"Book")) { + game_get_board(Game,board); + book_disp(board); + } + + } else if (match(string,"black")) { + + if (colour_is_black(game_turn(Game))) { + + State->computer[White] = TRUE; + State->computer[Black] = FALSE; + + XB->new_hack = TRUE; + XB->result = FALSE; + + mess(); + } + + } else if (match(string,"computer")) { + + XB->computer = TRUE; + + } else if (match(string,"draw")) { + if(option_find(Uci->option,"UCI_DrawOffers")){ + my_log("POLYGLOT draw from XB received"); + uci_send_option(Uci,"DrawOffer","%s","draw");} + } else if (match(string,"easy")) { + + XB->ponder = FALSE; + + mess(); + + } else if (match(string,"edit")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"exit")) { + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + XB->analyse = FALSE; + + mess(); + + } else if (match(string,"force")) { + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + mess(); + + } else if (match(string,"go")) { + + State->computer[game_turn(Game)] = TRUE; + State->computer[colour_opp(game_turn(Game))] = FALSE; + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + mess(); + + } else if (match(string,"hard")) { + + XB->ponder = TRUE; + + mess(); + + } else if (match(string,"hint")) { + + move=MoveNone; + game_get_board(Game,board); + if (option_get_bool(Option,"Book")) { + + move = book_move(board,FALSE); + } + if(move==MoveNone && State->hint_move!=MoveNone){ + move=State->hint_move; + + } + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + gui_send(GUI,"Hint: %s",move_string); + } + + } else if (match(string,"ics *")) { + + XB->ics = TRUE; + + } else if (match(string,"level * *:* *")) { + + XB->mps = atoi(Star[0]); + XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2])); + XB->inc = ((double)atoi(Star[3])); + + } else if (match(string,"level * * *")) { + + XB->mps = atoi(Star[0]); + XB->base = ((double)atoi(Star[1])) * 60.0; + XB->inc = ((double)atoi(Star[2])); + + } else if (match(string,"name *")) { + + my_string_set(&XB->name,Star[0]); + + } else if (match(string,"new")) { + + uci_send_isready_sync(Uci); + my_log("POLYGLOT NEW GAME\n"); + + option_set(Option,"Chess960","false"); + + game_clear(Game); + + if (XB->analyse) { + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + } else { + State->computer[White] = FALSE; + State->computer[Black] = TRUE; + } + + XB->new_hack = TRUE; + XB->result = FALSE; + + XB->depth_limit = FALSE; + XB->node_rate=-1; + + XB->computer = FALSE; + my_string_set(&XB->name,""); + + board_update(); + mess(); + + uci_send_ucinewgame(Uci); + + } else if (match(string,"nopost")) { + + XB->post = FALSE; + + } else if (match(string,"otim *")) { + + XB->opp_time = ((double)atoi(Star[0])) / 100.0; + if (XB->opp_time < 0.0) XB->opp_time = 0.0; + + } else if (match(string,"pause")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"ping *")) { + + // HACK; TODO: answer only after an engine move + + if (DelayPong) { + if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping + XB->ping = atoi(Star[0]); + uci_send_isready_sync(Uci); + } else { + ASSERT(XB->ping==-1); + gui_send(GUI,"pong %s",Star[0]); + } + } else if (match(string,"nps *")) { + + // fake WB play-by-nodes mode + XB->node_rate = atoi(Star[0]); + } else if (match(string,"playother")) { + + State->computer[game_turn(Game)] = FALSE; + State->computer[colour_opp(game_turn(Game))] = TRUE; + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + mess(); + + } else if (match(string,"post")) { + + XB->post = TRUE; + + } else if (match(string,"protover *")) { + XB->proto_ver = atoi(Star[0]); + ASSERT(XB->proto_ver>=2); + send_xboard_options(); + + } else if (match(string,"quit")) { + my_log("POLYGLOT *** \"quit\" from GUI ***\n"); + quit(); + } else if (match(string,"random")) { + + // ignore + + } else if (match(string,"rating * *")) { + + // ignore + + } else if (match(string,"remove")) { + + if (game_pos(Game) >= 2) { + + game_goto(Game,game_pos(Game)-2); + + ASSERT(!XB->new_hack); + XB->new_hack = FALSE; // HACK? + XB->result = FALSE; + + board_update(); + mess(); + } + + } else if (match(string,"rejected *")) { + + // ignore + + } else if (match(string,"reset")) { // protover 3? + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (FALSE + || match(string,"result * {*}") + || match(string,"result * {* }") + || match(string,"result * { *}") + || match(string,"result * { * }")) { + + my_log("POLYGLOT GAME END\n"); + + XB->result = TRUE; + + mess(); + + // book learning + + if (option_get_bool(Option,"Book") && + option_get_bool(Option,"BookLearn")) { + + if (FALSE) { + } else if (my_string_equal(Star[0],"1-0")) { + learn(+1); + } else if (my_string_equal(Star[0],"0-1")) { + learn(-1); + } else if (my_string_equal(Star[0],"1/2-1/2")) { + learn(0); + } + } + } else if (match(string,"resume")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"option *=*") || + match(string,"option * =*") || + match(string,"option *= *") || + match(string,"option * = *") + ){ + char *name=Star[0]; + char *value=Star[1]; + if(match(name, "Polyglot *")){ + char *pg_name=Star[0]; + polyglot_set_option(pg_name,value); + }else{ + option_t *opt=option_find(Uci->option,name); + if(opt){ + if(my_string_case_equal(opt->type,"check")){ + value=my_string_equal(value,"1")?"true":"false"; + } + start_protected_command(); + uci_send_option(Uci, name, "%s", value); + end_protected_command(); + }else{ + gui_send(GUI,"Error (unknown option): %s",name); + } + } + } else if (match(string,"option *")){ + char *name=Star[0]; + if(match(name, "Polyglot *")){ + char *pg_name=Star[0]; + polyglot_set_option(pg_name,""); + }else{ + start_protected_command(); + // value is ignored + if(!uci_send_option(Uci, name, "%s", "")){ + gui_send(GUI,"Error (unknown option): %s",name); + }; + end_protected_command(); + } + } else if (XB->has_feature_smp && match(string,"cores *")){ + int cores=atoi(Star[0]); + if(cores>=1){ + // updating the number of cores + my_log("POLYGLOT setting the number of cores to %d\n",cores); + start_protected_command(); + uci_set_threads(Uci,cores); + end_protected_command(); + } else{ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + } + } else if (match(string,"egtpath * *")){ + char *type=Star[0]; + char *path=Star[1]; + if(my_string_empty(path)){ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + }else{ + if(my_string_case_equal(type,"nalimov") && XB->has_feature_egt_nalimov){ + // updating NalimovPath + my_log("POLYGLOT setting the Nalimov path to %s\n",path); + start_protected_command(); + uci_send_option(Uci,"NalimovPath","%s",path); + end_protected_command(); + }else if(my_string_case_equal(type,"gaviota") && XB->has_feature_egt_gaviota){ + // updating GaviotaPath + my_log("POLYGLOT setting the Gaviota path to %s\n",path); + start_protected_command(); + uci_send_option(Uci,"GaviotaTbPath","%s",path); + end_protected_command(); + }else{ + // refuse + gui_send(GUI,"Error (unsupported table base format): %s",string); + } + } + } else if (XB->has_feature_memory && match(string,"memory *")){ + int memory = atoi(Star[0]); + int egt_cache; + int real_memory; + if(memory>=1){ + // updating the available memory + option_t *opt; + my_log("POLYGLOT setting the amount of memory to %dMb\n",memory); + if(XB->has_feature_egt_nalimov && (opt=option_find(Uci->option,"NalimovCache"))){ + egt_cache=atoi(opt->value); + }else if(XB->has_feature_egt_gaviota && + (opt=option_find(Uci->option,"GaviotaTbCache"))){ + egt_cache=atoi(opt->value); + }else{ + egt_cache=0; + } + my_log("POLYGLOT EGTB Cache is %dMb\n",egt_cache); + real_memory=memory-egt_cache; + if(real_memory>0){ + start_protected_command(); + uci_send_option(Uci,"Hash", "%d", real_memory); + end_protected_command(); + } + }else{ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + } + + } else if (match(string,"sd *")) { + + XB->depth_limit = TRUE; + XB->depth_max = atoi(Star[0]); + + } else if (match(string,"setboard *")) { + + my_log("POLYGLOT FEN %s\n",Star[0]); + + if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]); + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + XB->new_hack = TRUE; // HACK? + XB->result = FALSE; + + board_update(); + mess(); + + } else if (match(string,"st *")) { + + XB->time_limit = TRUE; + XB->time_max = ((double)atoi(Star[0])); + + } else if (match(string,"time *")) { + + XB->my_time = ((double)atoi(Star[0])) / 100.0; + if (XB->my_time < 0.0) XB->my_time = 0.0; + + } else if (match(string,"undo")) { + + if (game_pos(Game) >= 1) { + + game_goto(Game,game_pos(Game)-1); + + ASSERT(!XB->new_hack); + XB->new_hack = FALSE; // HACK? + XB->result = FALSE; + + board_update(); + mess(); + } + + } else if (match(string,"usermove *")) { + + game_get_board(Game,board); + move = move_from_san(Star[0],board); + + if (move != MoveNone && move_is_legal(move,board)) { + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + move_step(move); + no_mess(move); + + } else { + + gui_send(GUI,"Illegal move: %s",Star[0]); + } + + } else if (match(string,"variant *")) { + + if (my_string_equal(Star[0],"fischerandom")) { + option_set(Option,"Chess960","true"); + } else { + option_set(Option,"Chess960","false"); + } + + } else if (match(string,"white")) { + + if (colour_is_white(game_turn(Game))) { + + State->computer[White] = FALSE; + State->computer[Black] = TRUE; + + XB->new_hack = TRUE; + XB->result = FALSE; + + mess(); + } + + } else if (match(string,"xboard")) { + + // ignore + + } else if (match(string,".")) { // analyse info + + if (State->state == ANALYSE) { + int depth=Uci->best_depth;//HACK: don't clear engine-output window... + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) { + move_to_san(Uci->root_move,Uci->board,move_string,256); + gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d %s",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,Uci->root_move_nb-(Uci->root_move_pos+1),Uci->root_move_nb,move_string); + } else { + gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK + } + } + + } else if (match(string,"?")) { // move now + + if (State->state == THINK) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + // HACK: just send "stop" to the engine + + if (Uci->searching) { + my_log("POLYGLOT STOP SEARCH\n"); + engine_send(Engine,"stop"); + } + } + + } else { // unknown command, maybe a move? + + game_get_board(Game,board); + move = move_from_san(string,board); + + if (move != MoveNone && move_is_legal(move,board)) { + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + move_step(move); + no_mess(move); + + } else if (move != MoveNone) { + + gui_send(GUI,"Illegal move: %s",string); + + } else { + + gui_send(GUI,"Error (unknown command): %s",string); + } + } + return; +} + +// xboard2uci_engine_step() + +void xboard2uci_engine_step(char string[]) { + + int event; + board_t board[1]; + event = uci_parse(Uci,string); + + // react to events + + if ((event & EVENT_READY) != 0) { + + // the engine is now ready + + if (!Uci->ready) { + Uci->ready = TRUE; + // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1"); + } + + if (!DelayPong && XB->ping >= 0) { + gui_send(GUI,"pong %d",XB->ping); + XB->ping = -1; + } + } + + if ((event & EVENT_MOVE) != 0 && State->state == THINK) { + + // the engine is playing a move + + // MEGA HACK: estimate remaining time because XBoard won't send it! + + my_timer_stop(State->timer); + + XB->my_time -= my_timer_elapsed_real(State->timer); + XB->my_time += XB->inc; + if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base; + + if (XB->my_time < 0.0) XB->my_time = 0.0; + + // make sure to remember the ponder move + + State->hint_move=Uci->ponder_move; + + // play the engine move + + comp_move(Uci->best_move); + + } + + if ((event & EVENT_PV) != 0) { + + // the engine has sent a new PV + + send_pv(); + } + if ((event & EVENT_INFO) != 0) { + + // the engine has sent info + + send_info(); + } + if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){ + my_log("POYGLOT draw offer/resign from engine\n"); + if(option_find(Uci->option,"UCI_DrawOffers")){ + if(event & EVENT_DRAW) + gui_send(GUI,"offer draw"); + else + gui_send(GUI,"resign"); + } + } + if(((event & EVENT_ILLEGAL_MOVE)!=0) && (State->state == THINK)){ + game_get_board(Game,board); + if(board->turn==White){ + gui_send(GUI,"0-1 {polyglot: resign" + " (illegal engine move by white: %s)}",Uci->bestmove); + }else{ + gui_send(GUI,"1-0 {polyglot: resign" + " (illegal engine move by black: %s)}",Uci->bestmove); + } + board_disp(board); + XB->result = TRUE; + mess(); + } +} + +// format_xboard_option_line + +void format_xboard_option_line(char * option_line, option_t *opt){ + int j; + char option_string[StringSize]; + char *tmp; + strcpy(option_line,""); + // buffer overflow alert + strcat(option_line,"feature option=\""); + if(opt->mode&PG){ + strcat(option_line,"Polyglot "); + } + sprintf(option_string,"%s",opt->name); + strcat(option_line,option_string); + sprintf(option_string," -%s",opt->type); + strcat(option_line,option_string); + if(!IS_BUTTON(opt->type) && strcmp(opt->type,"combo")){ + if(strcmp(opt->type,"check")){ + sprintf(option_string," %s",opt->value); + }else{ + sprintf(option_string," %d", + my_string_case_equal(opt->value,"true")|| + my_string_equal(opt->value,"1") + ?1:0); + } + strcat(option_line,option_string); + } + if(IS_SPIN(opt->type)){ + sprintf(option_string," %s",opt->min); + strcat(option_line,option_string); + } + if(IS_SPIN(opt->type)){ + sprintf(option_string," %s",opt->max); + strcat(option_line,option_string); + } + for(j=0;jvar_nb;j++){ + if(!strcmp(opt->var[j],opt->value)){ + sprintf(option_string," *%s",opt->var[j]); + }else{ + sprintf(option_string," %s",opt->var[j]); + } + strcat(option_line,option_string); + if(j!=opt->var_nb-1){ + strcat(option_line," ///"); + } + } + strcat(option_line,"\""); + if(option_get_bool(Option,"WbWorkArounds") && + (tmp=strstr(option_line,"Draw"))){ + *tmp='d'; + my_log("POLYGLOT Decapitalizing \"Draw\" in option \"%s\"\n", + opt->name); + } +} + +// send_xboard_options() + +static void send_xboard_options(){ + + char egtfeature[StringSize]; + int tbs=0; + + gui_send(GUI,"feature done=0"); + + gui_send(GUI,"feature analyze=1"); + gui_send(GUI,"feature colors=0"); + gui_send(GUI,"feature draw=1"); + gui_send(GUI,"feature ics=1"); + gui_send(GUI,"feature myname=\"%s\"", + option_get_string(Option,"EngineName")); + gui_send(GUI,"feature name=1"); + gui_send(GUI,"feature pause=0"); + gui_send(GUI,"feature ping=1"); + gui_send(GUI,"feature playother=1"); + gui_send(GUI,"feature sigint=1"); + gui_send(GUI,"feature reuse=1"); + gui_send(GUI,"feature san=0"); + gui_send(GUI,"feature setboard=1"); + gui_send(GUI,"feature sigint=0"); + gui_send(GUI,"feature sigterm=0"); + gui_send(GUI,"feature time=1"); + gui_send(GUI,"feature usermove=1"); + gui_send(GUI,"feature nps=1"); + if (XB->has_feature_memory){ + gui_send(GUI,"feature memory=1"); + }else{ + gui_send(GUI,"feature memory=0"); + } + if (XB->has_feature_smp){ + gui_send(GUI,"feature smp=1"); + }else{ + gui_send(GUI,"feature smp=0"); + } + egtfeature[0]='\0'; + strncat(egtfeature,"feature egt=\"",StringSize); + if (XB->has_feature_egt_nalimov){ + tbs++; + strncat(egtfeature,"nalimov",StringSize-strlen(egtfeature)); + } + if (XB->has_feature_egt_gaviota){ + if(tbs>0){ + strncat(egtfeature,",",StringSize-strlen(egtfeature)); + } + strncat(egtfeature,"gaviota",StringSize-strlen(egtfeature)); + } + strncat(egtfeature,"\"",StringSize-strlen(egtfeature)); + egtfeature[StringSize-1]='\0'; + gui_send(GUI,egtfeature); + + if (option_find(Uci->option,"UCI_Chess960")) { + gui_send(GUI,"feature variants=\"normal,fischerandom\""); + } else { + gui_send(GUI,"feature variants=\"normal\""); + } + + xboard2uci_send_options(); +} + +void xboard2uci_send_options(){ + char option_line[StringSize]=""; + const char * name; + option_t *opt; + + option_start_iter(Uci->option); + while((opt=option_next(Uci->option))){ + if(my_string_case_equal(opt->name,"UCI_AnalyseMode")) continue; + if(my_string_case_equal(opt->name,"UCI_Opponent")) continue; + if(my_string_case_equal(opt->name,"UCI_Chess960")) continue; + if(my_string_case_equal(opt->name,"UCI_ShowCurrLine")) continue; + if(my_string_case_equal(opt->name,"UCI_ShowRefutations")) continue; + if(my_string_case_equal(opt->name,"UCI_ShredderbasesPath")) continue; + if(my_string_case_equal(opt->name,"UCI_SetPositionValue")) continue; + if(my_string_case_equal(opt->name,"UCI_DrawOffers")) continue; + if(my_string_case_equal(opt->name,"Ponder")) continue; + if(my_string_case_equal(opt->name,"Hash")) continue; + if(my_string_case_equal(opt->name,"NalimovPath")) continue; + if(my_string_case_equal(opt->name,"GaviotaTbPath")) continue; + if((name=uci_thread_option(Uci))!=NULL && + my_string_case_equal(opt->name,name)) continue; + format_xboard_option_line(option_line,opt); + + gui_send(GUI,"%s",option_line); + } + + + option_start_iter(Option); + while((opt=option_next(Option))){ + if(opt->mode &XBOARD){ + format_xboard_option_line(option_line,opt); + gui_send(GUI,"%s",option_line); + } + } + gui_send(GUI,"feature done=1"); + +} + +// report_best_score() + +static int report_best_score(){ + if(!option_get_bool(Option,"ScoreWhite") || + colour_is_white(Uci->board->turn)){ + return Uci->best_score; + }else{ + return -Uci->best_score; + } +} + +// comp_move() + +static void comp_move(int move) { + + board_t board[1]; + char string[256]; + + ASSERT(move_is_ok(move)); + + ASSERT(State->state==THINK); + ASSERT(!XB->analyse); + + if(option_get_bool(Option,"RepeatPV")) + send_pv(); // to update time and nodes + + // send the move + + game_get_board(Game,board); + + if (move_is_castle(move,board) && option_get_bool(Option,"Chess960")) { + if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O + } else { + if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n"); + } + + gui_send(GUI,"move %s",string); + + // resign? + + if (option_get_bool(Option,"Resign") && Uci->root_move_nb > 1) { + + if (Uci->best_score <= -abs(option_get_int(Option,"ResignScore"))) { + + State->resign_nb++; + my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":""); + + if (State->resign_nb >= option_get_int(Option,"ResignMoves")) { + my_log("POLYGLOT *** RESIGN ***\n"); + gui_send(GUI,"resign"); + } + + } else { + + if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb); + State->resign_nb = 0; + } + } + + // play the move + + move_step(move); + no_mess(move); +} + +// move_step() + +static void move_step(int move) { + + board_t board[1]; + char move_string[256]; + + ASSERT(move_is_ok(move)); + + // log + + game_get_board(Game,board); + + if (move != MoveNone && move_is_legal(move,board)) { + + move_to_san(move,board,move_string,256); + my_log("POLYGLOT MOVE %s\n",move_string); + + } else { + + move_to_can(move,board,move_string,256); + my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string); + board_disp(board); + + my_fatal("move_step(): illegal move \"%s\"\n",move_string); + } + + // play the move + + game_add_move(Game,move); + board_update(); +} + +// board_update() + +static void board_update() { + + // handle game end + + ASSERT(!XB->result); + + switch (game_status(Game)) { + case PLAYING: + break; + case WHITE_MATES: + gui_send(GUI,"1-0 {White mates}"); + break; + case BLACK_MATES: + gui_send(GUI,"0-1 {Black mates}"); + break; + case STALEMATE: + gui_send(GUI,"1/2-1/2 {Stalemate}"); + break; + case DRAW_MATERIAL: + gui_send(GUI,"1/2-1/2 {Draw by insufficient material}"); + break; + case DRAW_FIFTY: + gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}"); + break; + case DRAW_REPETITION: + gui_send(GUI,"1/2-1/2 {Draw by repetition}"); + break; + default: + ASSERT(FALSE); + break; + } +} + +// mess() + +static void mess() { + + // clear state variables + + State->resign_nb = 0; + State->exp_move = MoveNone; + my_timer_reset(State->timer); + + // abort a possible search + + stop_search(); + + // calculate the new state + + if (FALSE) { + } else if (!active()) { + State->state = WAIT; + my_log("POLYGLOT WAIT\n"); + } else if (XB->analyse) { + State->state = ANALYSE; + my_log("POLYGLOT ANALYSE\n"); + } else if (State->computer[game_turn(Game)]) { + State->state = THINK; + my_log("POLYGLOT THINK\n"); + } else { + State->state = WAIT; + my_log("POLYGLOT WAIT\n"); + } + + search_update(); +} + +// no_mess() + +static void no_mess(int move) { + + ASSERT(move_is_ok(move)); + + // just received a move, calculate the new state + + if (FALSE) { + + } else if (!active()) { + + stop_search(); // abort a possible search + + State->state = WAIT; + State->exp_move = MoveNone; + + my_log("POLYGLOT WAIT\n"); + + } else if (State->state == WAIT) { + + ASSERT(State->computer[game_turn(Game)]); + ASSERT(!State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + my_log("POLYGLOT WAIT -> THINK\n"); + + State->state = THINK; + State->exp_move = MoveNone; + + } else if (State->state == THINK) { + + ASSERT(!State->computer[game_turn(Game)]); + ASSERT(State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + if (ponder() && ponder_ok(Uci->ponder_move)) { + + my_log("POLYGLOT THINK -> PONDER\n"); + + State->state = PONDER; + State->exp_move = Uci->ponder_move; + + } else { + + my_log("POLYGLOT THINK -> WAIT\n"); + + State->state = WAIT; + State->exp_move = MoveNone; + } + + } else if (State->state == PONDER) { + + ASSERT(State->computer[game_turn(Game)]); + ASSERT(!State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + if (move == State->exp_move && Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_timer_start(State->timer);//also resets + + my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n"); + engine_send(Engine,"ponderhit"); + + State->state = THINK; + State->exp_move = MoveNone; + + send_pv(); // update display + + return; // do not launch a new search + + } else { + + my_log("POLYGLOT PONDER -> THINK (miss)\n"); + + stop_search(); + + State->state = THINK; + State->exp_move = MoveNone; + } + + } else if (State->state == ANALYSE) { + + ASSERT(XB->analyse); + + my_log("POLYGLOT ANALYSE -> ANALYSE\n"); + + stop_search(); + + } else { + + ASSERT(FALSE); + } + + search_update(); +} + +// start_protected_command() + +static void start_protected_command(){ + stop_search(); +} + +static void end_protected_command(){ + if(Uci->ready){ // not init faze + uci_send_isready_sync(Uci); // gobble up spurious "bestmove" + } + update_remaining_time(); + search_update(); // relaunch search if necessary +} + +// update_remaining_time() + +static void update_remaining_time(){ + double reduce; + if(State->timer->running){ + my_timer_stop(State->timer); + reduce = my_timer_elapsed_real(State->timer); + my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce); + XB->my_time -= reduce; + if(XB->my_time<0.0){ + XB->my_time=0.0; + } + } +} + + +// search_update() + +static void search_update() { + + int move; + int move_nb; + board_t board[1]; + + ASSERT(!Uci->searching); + + + + + // launch a new search if needed + + + + if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) { + + // [VdB] moved up as we need the move number + + game_get_board(Game,Uci->board); + + // opening book + + if (State->state == THINK && + option_get_bool(Option,"Book") && + Uci->board->move_nbboard,option_get_bool(Option,"BookRandom")); + + if (move != MoveNone && move_is_legal(move,Uci->board)) { + + my_log("POLYGLOT *BOOK MOVE*\n"); + + search_clear(); // clears Uci->ponder_move + Uci->best_move = move; + + board_copy(board,Uci->board); + move_do(board,move); + Uci->ponder_move = book_move(board,FALSE); // expected move = best book move + + Uci->best_pv[0] = Uci->best_move; + Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone + Uci->best_pv[2] = MoveNone; + + comp_move(Uci->best_move); + + return; + } + } + + // engine search + + my_log("POLYGLOT START SEARCH\n"); + + // options + + uci_send_option(Uci,"UCI_Chess960","%s", + option_get_bool(Option,"Chess960")?"true":"false"); + + if (option_get_int(Option,"UCIVersion") >= 2) { + uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name); + uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false"); + } + + uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false"); + + // position + + move = (State->state == PONDER) ? State->exp_move : MoveNone; + send_board(move); // updates Uci->board global variable + + // search + + if (State->state == THINK || State->state == PONDER) { + + engine_send_queue(Engine,"go"); + + if (XB->time_limit) { + + // fixed time per move + + if(XB->node_rate > 0){ + engine_send_queue(Engine, + " nodes %.0f", + XB->time_max*((double)XB->node_rate)); + }else{ + engine_send_queue(Engine, + " movetime %.0f", + XB->time_max*1000.0); + } + + } else { + + // time controls + + if(XB->node_rate > 0) { + double time; + move_nb = 40; + if (XB->mps != 0){ + move_nb = XB->mps - (Uci->board->move_nb % XB->mps); + } + time = XB->my_time / move_nb; + if(XB->inc != 0){ + time += XB->inc; + } + if(time > XB->my_time){ + time = XB->my_time; + } + engine_send_queue(Engine, + " nodes %.0f", + time*XB->node_rate); + } else { + + if (colour_is_white(Uci->board->turn)) { + engine_send_queue(Engine, + " wtime %.0f btime %.0f", + XB->my_time*1000.0,XB->opp_time*1000.0); + } else { + engine_send_queue(Engine, + " wtime %.0f btime %.0f", + XB->opp_time*1000.0,XB->my_time*1000.0); + } + + if (XB->inc != 0.0){ + engine_send_queue(Engine, + " winc %.0f binc %.0f", + XB->inc*1000.0,XB->inc*1000.0); + } + if (XB->mps != 0) { + + move_nb = XB->mps - (Uci->board->move_nb % XB->mps); + ASSERT(move_nb>=1&&move_nb<=XB->mps); + + engine_send_queue(Engine," movestogo %d",move_nb); + } + } + } + if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max); + + if (State->state == PONDER) engine_send_queue(Engine," ponder"); + + engine_send(Engine,""); // newline + + } else if (State->state == ANALYSE) { + + engine_send(Engine,"go infinite"); + + } else { + + ASSERT(FALSE); + } + + // init search info + + ASSERT(!Uci->searching); + + search_clear(); + + Uci->searching = TRUE; + Uci->pending_nb++; + } +} + +// search_clear() + +static void search_clear() { + + uci_clear(Uci); + + // TODO: MOVE ME + + my_timer_start(State->timer);//also resets +} + +// active() + +static bool active() { + + // position state + + if (game_status(Game) != PLAYING) return FALSE; // game ended + + // xboard state + + if (XB->analyse) return TRUE; // analysing + if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode + if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game + + return TRUE; // playing +} + +// ponder() + +static bool ponder() { + + return XB->ponder && (option_get_bool(Option,"CanPonder") || + option_find(Uci->option,"Ponder")); +} +// ponder_ok() + +static bool ponder_ok(int move) { + int status; + board_t board[1]; + + ASSERT(move==MoveNone||move_is_ok(move)); + + // legal ponder move? + + if (move == MoveNone) return FALSE; + + game_get_board(Game,board); + if (!move_is_legal(move,board)) return FALSE; + + // UCI-legal resulting position? + + game_add_move(Game,move); + + game_get_board(Game,board); + status = game_status(Game); + + game_rem_move(Game); + + if (status != PLAYING) return FALSE; // game ended + + if (option_get_bool(Option,"Book") && is_in_book(board)) { + return FALSE; + } + + return TRUE; +} + +// stop_search() + +static void stop_search() { + + if (Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_log("POLYGLOT STOP SEARCH\n"); + +/* + engine_send(Engine,"stop"); + Uci->searching = FALSE; +*/ + + if (option_get_bool(Option,"SyncStop")) { + uci_send_stop_sync(Uci); + } else { + uci_send_stop(Uci); + } + } +} + +// send_board() + +static void send_board(int extra_move) { + + char fen[256]; + int start, end; + board_t board[1]; + int pos; + int move; + char string[256]; + + ASSERT(extra_move==MoveNone||move_is_ok(extra_move)); + + ASSERT(!Uci->searching); + + // init + + game_get_board(Game,Uci->board); + if (extra_move != MoveNone) move_do(Uci->board,extra_move); + + board_to_fen(Uci->board,fen,256); + my_log("POLYGLOT FEN %s\n",fen); + + ASSERT(board_can_play(Uci->board)); + + // more init + + start = 0; + end = game_pos(Game); + ASSERT(end>=start); + + // position + + game_get_board_ex(Game,board,start); + board_to_fen(board,string,256); + + engine_send_queue(Engine,"position"); + + if (my_string_equal(string,StartFen)) { + engine_send_queue(Engine," startpos"); + } else { + engine_send_queue(Engine," fen %s",string); + } + + // move list + + if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves"); + + for (pos = start; pos < end; pos++) { // game moves + + move = game_move(Game,pos); + + move_to_can(move,board,string,256); + engine_send_queue(Engine," %s",string); + + move_do(board,move); + } + + if (extra_move != MoveNone) { // move to ponder on + move_to_can(extra_move,board,string,256); + engine_send_queue(Engine," %s",string); + } + + // end + + engine_send(Engine,""); // newline +} + +// send_info() + +static void send_info() { + int min_depth; + if(option_get_bool(Option,"WbWorkArounds2")){ + // Silly bug in some versions of WinBoard. + // depth <=1 clears the engine output window. + // Why shouldn't an engine be allowed to send info at depth 1? + min_depth=2; + }else{ + min_depth=1; + } + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth>min_depth?Uci->best_depth:min_depth, + 0,0,0.0,0,Uci->info); +} + +// send_pv() + +static void send_pv() { + + char pv_string[StringSize]; + board_t board[1]; + int move; + char move_string[StringSize]; + + ASSERT(State->state!=WAIT); + + if (Uci->best_depth == 0) return; + + // xboard search information + + if (XB->post) { + + if (State->state == THINK || State->state == ANALYSE) { + + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + + if(Uci->depth==-1) //hack to clear the engine output window + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb); + + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string); + + } else if (State->state == PONDER && + option_get_bool(Option,"ShowPonder")) { + + game_get_board(Game,board); + move = State->exp_move; + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" (%s) %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,move_string,pv_string); + } + } + } + + // kibitz + + if ((Uci->searching && + option_get_bool(Option,"KibitzPV") && + Uci->time >= option_get_double(Option,"KibitzDelay")) + || (!Uci->searching && option_get_bool(Option,"KibitzMove"))) { + + if (State->state == THINK || State->state == ANALYSE) { + + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + if(kibitz_throttle(Uci->searching)){ + gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"%s\"",option_get_string(Option,"KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,((double)report_best_score())/100.0,pv_string); + } + } else if (State->state == PONDER) { + + game_get_board(Game,board); + move = State->exp_move; + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + if(kibitz_throttle(Uci->searching)){ + gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string(Option,"KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,((double)report_best_score())/100.0,move_string,pv_string); + } + } + } + } +} + +// kibitz_throttle() + +static bool kibitz_throttle(bool searching){ + time_t curr_time; + static time_t lastKibitzMove=0; + static time_t lastKibitzPV=0; + curr_time = time(NULL); + if(searching){ // KibitzPV + if(curr_time >= + (option_get_int(Option,"KibitzInterval") + lastKibitzPV)){ + lastKibitzPV=curr_time; + return TRUE; + } + }else{ // KibitzMove + if(curr_time >= + (option_get_int(Option,"KibitzInterval") + lastKibitzMove)){ + lastKibitzPV=curr_time; + lastKibitzMove=curr_time; + return TRUE; + } + } + return FALSE; +} + +// learn() + +static void learn(int result) { + + int pos; + board_t board[1]; + int move; + + ASSERT(result>=-1&&result<=+1); + + ASSERT(XB->result); + ASSERT(State->computer[White]||State->computer[Black]); + + // init + + pos = 0; + + if (FALSE) { + } else if (State->computer[White]) { + pos = 0; + } else if (State->computer[Black]) { + pos = 1; + result = -result; + } else { + my_fatal("learn(): unknown side\n"); + } + + if (FALSE) { + } else if (result > 0) { + my_log("POLYGLOT *LEARN WIN*\n"); + } else if (result < 0) { + my_log("POLYGLOT *LEARN LOSS*\n"); + } else { + my_log("POLYGLOT *LEARN DRAW*\n"); + } + + // loop + + for (; pos < Game->size; pos += 2) { + + game_get_board_ex(Game,board,pos); + move = game_move(Game,pos); + + book_learn_move(board,move,result); + } + + book_flush(); +} + +// end of xboard2uci.c diff --git a/xboard2uci.h b/xboard2uci.h index 94eaa8c..c0ad4ad 100644 --- a/xboard2uci.h +++ b/xboard2uci.h @@ -1,24 +1,24 @@ - -// xboard2uci.h - -#ifndef XBOARD2UCI_H -#define XBOARD2UCI_H - -// includes - -#include "util.h" - -// types - -// functions - -extern void xboard2uci_init (); -extern void xboard2uci_gui_step (char string[]); -extern void xboard2uci_engine_step (char string[]); -extern void xboard2uci_send_options (); - - -#endif // !defined XBOARD2UCI_H - -// end of xboard2uci.h - + +// xboard2uci.h + +#ifndef XBOARD2UCI_H +#define XBOARD2UCI_H + +// includes + +#include "util.h" + +// types + +// functions + +extern void xboard2uci_init (); +extern void xboard2uci_gui_step (char string[]); +extern void xboard2uci_engine_step (char string[]); +extern void xboard2uci_send_options (); + + +#endif // !defined XBOARD2UCI_H + +// end of xboard2uci.h + -- 1.7.0.4