From 5b6e05735f61e17957ea94b65f82d5c8272bbb6d Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sat, 17 May 2025 20:53:36 -0700 Subject: [PATCH] critical bugfix + refactor bench 1245854 --- LICENSE.txt => LICENSE | 150 +- README.md | 205 +- Serendipity/.gitignore | 201 + Serendipity/pom.xml | 126 + .../Serendipity/Chess/AccumulatorDiff.java | 65 + .../games/Serendipity/Chess/Attacks.java | 440 ++ .../games/Serendipity/Chess/Bitboard.java | 304 + .../shawn/games/Serendipity/Chess/Board.java | 2565 +++++++ .../games/Serendipity/Chess/BoardContext.java | 901 +++ .../games/Serendipity/Chess/CastleRight.java | 67 + .../games/Serendipity/Chess/Constants.java | 133 + .../shawn/games/Serendipity/Chess/File.java | 109 + .../games/Serendipity/Chess/MoveBackup.java | 445 ++ .../shawn/games/Serendipity/Chess/Piece.java | 223 + .../games/Serendipity/Chess/PieceType.java | 145 + .../shawn/games/Serendipity/Chess/Rank.java | 109 + .../shawn/games/Serendipity/Chess/Side.java | 69 + .../shawn/games/Serendipity/Chess/Square.java | 453 ++ .../games/Serendipity/Chess/move/Move.java | 189 + .../Chess/move/MoveConversionException.java | 66 + .../Serendipity/Chess/move/MoveException.java | 67 + .../Serendipity/Chess/move/MoveGenerator.java | 497 ++ .../Chess/move/MoveGeneratorException.java | 65 + .../Serendipity/Chess/move/MoveList.java | 1017 +++ .../Serendipity/Chess/util/StringUtil.java | 201 + .../Chess/util/XorShiftRandom.java | 56 + .../Serendipity/NNUE/AccumulatorCache.java | 79 + .../Serendipity/NNUE/AccumulatorStack.java | 310 + .../games/Serendipity/NNUE/Inference.java | 39 + .../Serendipity/NNUE/InferenceChooser.java | 35 + .../shawn/games/Serendipity/NNUE/NNUE.java | 168 + .../games/Serendipity/NNUE/SIMDInference.java | 151 + .../Serendipity/NNUE/ScalarInference.java | 111 + .../games/Serendipity/NNUE/module-info.java | 24 + .../shawn/games/Serendipity/PeSTO/PeSTO.java | 381 + .../games/Serendipity/Search/AlphaBeta.java | 956 +++ .../Search/Debug/AveragedEntry.java | 43 + .../Serendipity/Search/Debug/DebugEntry.java | 25 + .../Serendipity/Search/Debug/Debugger.java | 61 + .../Search/Debug/FrequencyEntry.java | 47 + .../Search/History/CaptureHistory.java | 104 + .../Search/History/ContinuationHistories.java | 63 + .../Search/History/FromToHistory.java | 80 + .../Serendipity/Search/History/History.java | 32 + .../Search/History/PieceToHistory.java | 81 + .../games/Serendipity/Search/Limits.java | 99 + .../Search/Listener/FinalReport.java | 32 + .../Search/Listener/ISearchListener.java | 27 + .../Search/Listener/SearchReport.java | 47 + .../games/Serendipity/Search/MovePicker.java | 247 + .../games/Serendipity/Search/SearchStack.java | 67 + .../Serendipity/Search/SharedThreadData.java | 44 + .../games/Serendipity/Search/ThreadData.java | 79 + .../Serendipity/Search/ThreadManager.java | 172 + .../games/Serendipity/Search/TimeManager.java | 96 + .../Serendipity/Search/TimeOutException.java | 25 + .../Search/TranspositionTable.java | 220 + .../shawn/games/Serendipity/UCI/Bench.java | 111 + .../games/Serendipity/UCI/IntegerOption.java | 81 + .../games/Serendipity/UCI/StringOption.java | 57 + .../shawn/games/Serendipity/UCI/Tunable.java | 29 + .../org/shawn/games/Serendipity/UCI/UCI.java | 364 + .../games/Serendipity/UCI/UCIListener.java | 84 + .../games/Serendipity/UCI/UCIOption.java | 27 + .../shawn/games/Serendipity/UCI/WDLModel.java | 90 + Serendipity/src/main/resources/.gitignore | 1 + .../games/Serendipity/AccumulatorTest.java | 86 + .../org/shawn/games/Serendipity/SEETest.java | 295 + .../Serendipity/TranspositionTableTest.java | 58 + header.sh | 17 + makefile | 67 +- perft.txt | 6752 ----------------- src/BBmacros.cpp | 15 - src/BBmacros.h | 181 - src/Game.cpp | 288 - src/Game.h | 178 - src/Perseus.cpp | 112 - src/Position.cpp | 1798 ----- src/Position.h | 274 - src/bench.cpp | 85 - src/bench.h | 3 - src/build.mk | 74 - src/constants.cpp | 14 - src/constants.h | 268 - src/evaluation.cpp | 1908 ----- src/evaluation.h | 191 - src/history.cpp | 82 - src/history.h | 140 - src/magic.cpp | 108 - src/magic.h | 179 - src/makefile | 13 - src/move.cpp | 61 - src/move.h | 120 - src/movegen.cpp | 212 - src/movegen.h | 219 - src/random.cpp | 30 - src/random.h | 18 - src/search.cpp | 797 -- src/tables.cpp | 381 - src/tables.h | 177 - src/tt.cpp | 71 - src/tt.h | 117 - src/types.h | 121 - src/uci.cpp | 612 -- src/uci.h | 100 - src/visualizer.ipynb | 918 --- src/zobrist.cpp | 54 - src/zobrist.h | 18 - utils/spsa_utils/constants_sub.py | 39 - utils/spsa_utils/original.txt | 122 - utils/spsa_utils/output.txt | 122 - utils/spsa_utils/spsa_out.txt | 77 - 112 files changed, 14039 insertions(+), 17190 deletions(-) rename LICENSE.txt => LICENSE (86%) create mode 100644 Serendipity/.gitignore create mode 100644 Serendipity/pom.xml create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/AccumulatorDiff.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Attacks.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Bitboard.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Board.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/BoardContext.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/CastleRight.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Constants.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/File.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/MoveBackup.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Piece.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/PieceType.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Rank.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Side.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Square.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/Move.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveConversionException.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveException.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGenerator.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGeneratorException.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveList.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/StringUtil.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/XorShiftRandom.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorCache.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorStack.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/Inference.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/InferenceChooser.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/NNUE.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/SIMDInference.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/ScalarInference.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/module-info.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/PeSTO/PeSTO.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/AlphaBeta.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/AveragedEntry.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/DebugEntry.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/Debugger.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/FrequencyEntry.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/CaptureHistory.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/ContinuationHistories.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/FromToHistory.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/History.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/PieceToHistory.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Limits.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/FinalReport.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/ISearchListener.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/SearchReport.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/MovePicker.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SearchStack.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SharedThreadData.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadData.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadManager.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeManager.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeOutException.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TranspositionTable.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Bench.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/IntegerOption.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/StringOption.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Tunable.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCI.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIListener.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIOption.java create mode 100644 Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/WDLModel.java create mode 100644 Serendipity/src/main/resources/.gitignore create mode 100644 Serendipity/src/test/java/org/shawn/games/Serendipity/AccumulatorTest.java create mode 100644 Serendipity/src/test/java/org/shawn/games/Serendipity/SEETest.java create mode 100644 Serendipity/src/test/java/org/shawn/games/Serendipity/TranspositionTableTest.java create mode 100644 header.sh delete mode 100644 perft.txt delete mode 100644 src/BBmacros.cpp delete mode 100644 src/BBmacros.h delete mode 100644 src/Game.cpp delete mode 100644 src/Game.h delete mode 100644 src/Perseus.cpp delete mode 100644 src/Position.cpp delete mode 100644 src/Position.h delete mode 100644 src/bench.cpp delete mode 100644 src/bench.h delete mode 100644 src/build.mk delete mode 100644 src/constants.cpp delete mode 100644 src/constants.h delete mode 100644 src/evaluation.cpp delete mode 100644 src/evaluation.h delete mode 100644 src/history.cpp delete mode 100644 src/history.h delete mode 100644 src/magic.cpp delete mode 100644 src/magic.h delete mode 100644 src/makefile delete mode 100644 src/move.cpp delete mode 100644 src/move.h delete mode 100644 src/movegen.cpp delete mode 100644 src/movegen.h delete mode 100644 src/random.cpp delete mode 100644 src/random.h delete mode 100644 src/search.cpp delete mode 100644 src/tables.cpp delete mode 100644 src/tables.h delete mode 100644 src/tt.cpp delete mode 100644 src/tt.h delete mode 100644 src/types.h delete mode 100644 src/uci.cpp delete mode 100644 src/uci.h delete mode 100644 src/visualizer.ipynb delete mode 100644 src/zobrist.cpp delete mode 100644 src/zobrist.h delete mode 100644 utils/spsa_utils/constants_sub.py delete mode 100644 utils/spsa_utils/original.txt delete mode 100644 utils/spsa_utils/output.txt delete mode 100644 utils/spsa_utils/spsa_out.txt diff --git a/LICENSE.txt b/LICENSE similarity index 86% rename from LICENSE.txt rename to LICENSE index 94a9ed0..f36a7b7 100644 --- a/LICENSE.txt +++ b/LICENSE @@ -1,5 +1,5 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies @@ -7,17 +7,15 @@ Preamble - The GNU General Public License is a free, copyleft license for -software and other kinds of works. + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to +our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. +software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you @@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. The precise terms and conditions for copying, distribution and modification follow. @@ -72,7 +60,7 @@ modification follow. 0. Definitions. - "This License" refers to version 3 of the GNU General Public License. + "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. @@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single +under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General +Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published +GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's +versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -632,43 +630,33 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) + + Copyright (C) {{ year }} {{ organization }} 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 + it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see +For more information on this, and how to apply and follow the GNU AGPL, see . - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.md b/README.md index 5847961..5000226 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,191 @@ -# Perseus Chess Engine +
+

+ Serendipity +

+
-Perseus is a UCI-compliant chess engine written in C++. It's designed to play chess at a competitive level and provides a rich set of features for both developers and users. +Serendipity is a UCI chess engine written in the Java programming language. With a CCRL rating of more than 3500 elo, it is the strongest Java chess engine in the world. -## Features +### History -- UCI Protocol: Perseus fully supports the Universal Chess Interface (UCI) protocol, allowing it to seamlessly integrate with various chess GUIs (Graphical User Interfaces). -- Search Algorithms: The engine implements advanced search algorithms such as Alpha-Beta pruning with various enhancements like Transposition Tables, Iterative Deepening, and Quiescence Search. Refer to `search.cpp` for the code. -- Evaluation Function: Perseus incorporates an evaluation function that assesses the strength of a given chess position based on factors like piece values, mobility, and more. -- Bitboard Representation: Utilizing efficient bitboard representation, Perseus achieves fast move generation and evaluation. +In early January 2024, I was inspired by a [tom7 video][elo_world] to create a [chess arena][chess_arena] in Java. +It didn't get very far, however, as I soon focused all my development effort in a minimax implementation. -## Usage +In March, I began to work on NNUE support. +After completing NNUE, the strength of Serendipity skyrocketed, I had several commits with gains of over 100 Elo. +On March 27, I published my [first release][first_release]. The results were much better than I had expected, as it turns out that I have +vastly underestimated Serendipity's strength. Two days later, I made my first Stockfish commit. -- Compile: Compile the Perseus source code just by using `make`. -- Run: Execute the compiled binary file. -- Integrate: Connect Perseus to your preferred chess GUI using the UCI protocol. -- Configure: Adjust engine parameters and options as desired to customize its behavior. -- Play: Enjoy playing chess against Perseus or watch it compete against other engines. +In May, four other engine developers and I co-founded an [OpenBench][openbench_url] instance, where Serendipity testing happens to this day. -## Configuration Options +In August, I implemented multithreading for Serendipity's first debut Top Chess Engines Championship. -Perseus provides several configuration options that can be adjusted via the 'setoption' . One can adjust the hash table size, as well as some of the many heuristic's parameters to his liking. The Weather Factory framework is used to tune these parameters. +#### Timeline -For a comprehensive list of available options and their descriptions, refer to the source code in `uci.cpp`. +- January 9, 2024: First commit to arena project +- January 12, 2024: First main repo commit +- March 10, 2024: NNUE support +- March 27, 2024: First release of Serendipity +- May 24, 2024: OpenBench instance founded +- August 23, 2024: Multithreading support +- August 26, 2024: TCEC Debut -## Contributions +### Strength -Contributions to Perseus are welcome! Whether it's bug fixes, performance improvements, or new features, feel free to fork the repository, make your changes, and submit a pull request. +As of November 2024, Serendipity is the strongest Java engine in the world and around top 50 overall. -In the pull request, make sure to include the bench of the submitted version, and the SPRT result of the main vs submitted engine. SPRT results are not needed if the change doesn't impact the engine playing itself (e.g. correcting a string, formatting, adding comments etc...). +
-## License +| Version | [CCRL Blitz][ccrl-blitz] | [CCRL 40/15][ccrl-4040] | +|:-------:|:------------------------:|:-----------------------:| +| v0.1 | - | 3227 | +| v0.2 | 3411 | - | +| v0.3 | - | 3390 | +| v0.4 | 3516 | 3446 | +| v1.0 | 3559 | 3487 | -Perseus is distributed under the GNU General Public License. See the LICENSE file for details. +
-## Credits +### Build -Perseus is developed and maintained by me. Special thanks to BluefeverSoftware and CodeMonkeyKing for their evergreen videos that are the starting point for nearly anyone that approaches Computer Chess Programming, the whole Stockfish Discord whose users are always polite and ready to help, and PGG106 for both his help and a lot of the ideas which are (heavily) inspired from his engine. -Also Cie is a strange individual. Just saying. But gives ELO. So we will tolerate. -Viz is an amazing source of ancient HCE druid knowledge, pretty wholesome. -Viren does not give ELO. In fact Viren owes us ELO. -Ty cj for the lmr granularity idea. Very wholesome. -Thanks to shawn for helping with both ideas (rip givesCheck lmp) and cores (that thing is fast af). -Yes, I capitalize ELO not because it is an acronym, but because it sounds funny. +To build Serendipity from source, install [`maven`][maven_url], [`make`][make_url], [`git`][git_url] and [`wget`][wget_url]. Then run the following: + +```bash +git clone git@github.com:xu-shawn/Serendipity.git +cd Serendipity +make +``` + +This will produce two versions of Serendipity executable: `Serendipity-Dev` and `Serendipity.jar`. + +`Serendipity-Dev` is a standalone executable that can be run on Linux or MacOS directly. + +`Serendipity.jar` is cross platform, but it requires extra commands to run. See section below for more details. + +### Run + +Serendipity only supports Java version 17 or higher due to its dependency on Java's (incubating) [Vector API][vector_api]. To run `Serendipity.jar`: + +``` +java -jar --add-modules jdk.incubator.vector Serendipity.jar +``` + +Alternatively, if you are on Linux/MacOS, you can also opt to run the Serendipity executable file: + +``` +./Serendipity +``` + +### Search + +- Efficiency + - Iterative Deepening + - Aspiration Windows + - Principle Variation Search (PVS) + - Transposition Table + - Shared Transposition Table + - 10-byte entries + - Parallel array implementation +- Multithreading + - Lazy SMP +- Move Ordering + - Butterfly History + - Capture History + - Continuation Histories + - 1-ply Continuation History + - 2-ply Continuation History + - 4-ply Continuation History + - 6-ply Continuation History + - Ordering of Captures by Static Exchange Evaluation (SEE) +- Selectivity + - Quiescent Search (QS) + - QS SEE Pruning + - QS Futility Pruning + - Extensions + - Singular Extensions + - 1-ply Extension of PV Nodes + - 2-ply Extension of Non-PV Nodes + - Pruning + - Before Moves Loop + - Null Move Pruning + - Reverse Futility Pruning + - Razoring + - Moves Loop Prunings + - Futility Pruning + - PVS SEE Pruning + - Multi-cut Pruning + - Reductions + - Late Move Reductions + - Internal Iterative Reductions + +### Evaluation + +Serendipity relies on a side-relative and efficiently updatable neural network for evaluation. +This avoids full network refreshes between moves, which helps the engine obtain good evaluation with reasonable speed. + +The description of the network architecture, as well as the training procedure, is beyond the scope of this document. + +### Acknowledgements + +Big shoutout to everyone who has [contributed][contributors_url] ideas or code to this project. + +Serendipity depends on the following libraries: +- [`chesslib`][chesslib_url] for move generation and board representation +- [`JUnit`][JUnit_url] for testing critical components of the engine + +Serendipity's neural network is trained using [bullet][bullet_url] and on open data generously provided by the [Leela Chess Zero][lc0_url] project. + +Testing Serendipity requires thosands of hours of compute, so thanks to everyone on our [OpenBench instance][furybench_url] for their contributions, however big or small. +The names of these people are listed below, by alphabetical order: +- [ArjunBasandrai][ArjunBasandrai] +- [aronpetko][aronpetko] +- [gab8192][gab8192] +- [Haxk20][Haxk20] +- [Jochengehtab][Jochengehtab] +- [noobpwnftw][noobpwnftw] +- Styxdoto +- [Vast342][Vast342] +- [Witek902][Witek902] +- [yl25946][yl25946] +- [Yoshie2000][Yoshie2000] + +Thanks to engine testers such as CCRL and Silvian Rucsandescu for running and testing the engine. + +Finally, thanks to everyone on the [Stockfish Discord][sf_discord], [Engine Programming Discord][ep_discord], and the unofficial [CPW Discord][cpw_discord] for being kind, knowledgeable, and collaborative. + +[elo_world]: https://www.youtube.com/watch?v=DpXy041BIlA +[chess_arena]: https://github.com/xu-shawn/SimplerChessEngine +[first_release]: https://github.com/xu-shawn/Serendipity/releases/tag/v0.1 +[openbench_url]: https://github.com/AndyGrant/OpenBench + +[maven_url]: https://maven.apache.org/ +[make_url]: https://www.gnu.org/software/make/ +[git_url]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +[wget_url]: https://www.gnu.org/software/wget/ + +[vector_api]: https://docs.oracle.com/en/java/javase/17/docs/api/jdk.incubator.vector/jdk/incubator/vector/Vector.html + +[ccrl-blitz]: https://www.computerchess.org.uk/ccrl/404/cgi/compare_engines.cgi?family=Serendipity&print=Rating+list +[ccrl-4040]: https://www.computerchess.org.uk/ccrl/4040/cgi/compare_engines.cgi?family=Serendipity&print=Rating+list + +[contributors_url]: https://github.com/xu-shawn/Serendipity/graphs/contributors +[chesslib_url]: https://github.com/bhlangonijr/chesslib +[JUnit_url]: https://github.com/junit-team/junit5 +[bullet_url]: https://github.com/jw1912/bullet +[lc0_url]: https://lczero.org/ +[furybench_url]: https://chess.aronpetkovski.com/ + +[ArjunBasandrai]: https://github.com/ArjunBasandrai +[aronpetko]: https://github.com/aronpetko +[gab8192]: https://github.com/gab8192 +[Haxk20]: https://github.com/Haxk20 +[Jochengehtab]: https://github.com/Jochengehtab +[noobpwnftw]: https://github.com/noobpwnftw +[Vast342]: https://github.com/Vast342 +[Witek902]: https://github.com/Witek902 +[yl25946]: https://github.com/yl25946 +[Yoshie2000]: https://github.com/Yoshie2000 + +[sf_discord]: https://discord.com/invite/GWDRS3kU6R +[ep_discord]: https://discord.com/invite/F6W6mMsTGN +[cpw_discord]: https://discord.gg/kWDrFSB2GG diff --git a/Serendipity/.gitignore b/Serendipity/.gitignore new file mode 100644 index 0000000..aac10b3 --- /dev/null +++ b/Serendipity/.gitignore @@ -0,0 +1,201 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + + +# Created by https://www.gitignore.io/api/git,java,maven,eclipse,windows + +### Eclipse ### + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core +.project + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Annotation Processing +.apt_generated + +.sts4-cache/ + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Some additional ignores (sort later) +*.DS_Store +*.sw? +.#* +*# +*~ +.classpath +.project +.settings +bin +build +target +dependency-reduced-pom.xml +*.sublime-* +/scratch +.gradle +README.html +*.iml +.idea +.exercism diff --git a/Serendipity/pom.xml b/Serendipity/pom.xml new file mode 100644 index 0000000..c72d00f --- /dev/null +++ b/Serendipity/pom.xml @@ -0,0 +1,126 @@ + + + + 4.0.0 + + org.shawn.games + Serendipity + ${revision} + + Serendipity + + http://www.example.com + + + UTF-8 + 17 + 17 + Test + + + + + maven-central + https://repo1.maven.org/maven2 + + + jitpack.io + https://jitpack.io + + + + + + org.apache.commons + commons-lang3 + 3.17.0 + + + junit + junit + 4.11 + test + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 3.5.0 + + + maven-jar-plugin + 3.0.2 + + + + true + lib/ + org.shawn.games.Serendipity.UCI.UCI + + + + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + + maven-shade-plugin + 2.3 + + + + package + + shade + + + + + + + org.shawn.games.Serendipity.UCI.UCI + + + + + + + + + diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/AccumulatorDiff.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/AccumulatorDiff.java new file mode 100644 index 0000000..3250e25 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/AccumulatorDiff.java @@ -0,0 +1,65 @@ +package org.shawn.games.Serendipity.Chess; + +public class AccumulatorDiff +{ + public class DiffInfo + { + public final Piece piece; + public final Square square; + + public DiffInfo(Piece piece, Square square) + { + this.piece = piece; + this.square = square; + } + } + + private int addedCount; + private DiffInfo[] added; + + private int removedCount; + private DiffInfo[] removed; + + public AccumulatorDiff() + { + this.addedCount = 0; + this.added = new DiffInfo[2]; + + this.removedCount = 0; + this.removed = new DiffInfo[2]; + } + + public void addPiece(Piece piece, Square square) + { + this.added[this.addedCount] = new DiffInfo(piece, square); + this.addedCount++; + } + + public void removePiece(Piece piece, Square square) + { + this.removed[this.removedCount] = new DiffInfo(piece, square); + this.removedCount++; + } + + public int getAddedCount() + { + return this.addedCount; + } + + public int getRemovedCount() + { + return this.removedCount; + } + + public DiffInfo getAdded(int index) + { + assert index < getAddedCount(); + return this.added[index]; + } + + public DiffInfo getRemoved(int index) + { + assert index < getRemovedCount(); + return this.removed[index]; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Attacks.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Attacks.java new file mode 100644 index 0000000..9dd34af --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Attacks.java @@ -0,0 +1,440 @@ +package org.shawn.games.Serendipity.Chess; + +public class Attacks +{ + private static final long[] kingAttacks; + private static final long[] knightAttacks; + private static final long[] bishopMask; + private static final int[] bishopShift; + private static final long[] bishopMagic; + private static final long[][] bishopAttacks; + private static final long[] rookMask; + private static final int[] rookShift; + private static final long[] rookMagic; + private static final long[][] rookAttacks; + + static + { + knightAttacks = new long[64]; + kingAttacks = new long[64]; + bishopMask = new long[64]; + bishopShift = new int[64]; + bishopMagic = Precomputed.bishopMagic; + bishopAttacks = new long[64][512]; + rookMask = new long[64]; + rookShift = new int[64]; + rookAttacks = new long[64][4096]; + rookMagic = Precomputed.rookMagic; + + for (int sqIdx = 0; sqIdx < 64; sqIdx++) + { + final Square sq = Square.values()[sqIdx]; + + knightAttacks[sqIdx] = generateKnightAttacks(sq); + kingAttacks[sqIdx] = generateKingAttacks(sq); + + bishopMask[sqIdx] = generateBishopMask(sq); + bishopShift[sqIdx] = generateMagicShift(bishopMask[sqIdx]); + bishopAttacks[sqIdx] = generateBishopAttacks(sq, bishopMask[sqIdx], bishopMagic[sqIdx], bishopShift[sqIdx]); + + rookMask[sqIdx] = generateRookMask(sq); + rookShift[sqIdx] = generateMagicShift(rookMask[sqIdx]); + rookAttacks[sqIdx] = generateRookAttacks(sq, rookMask[sqIdx], rookMagic[sqIdx], rookShift[sqIdx]); + } + } + + public enum Direction + { + NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST + } + + public static Square shift(Square square, Direction direction) + { + return Square.fromBitboard(shift(square.getBitboard(), direction)); + } + + public static long shift(long bitboard, Direction direction) + { + switch (direction) + { + case NORTH: + return bitboard << 8; + case SOUTH: + return bitboard >>> 8; + case EAST: + return (bitboard & ~Bitboard.fileBB[7]) << 1; + case WEST: + return (bitboard & ~Bitboard.fileBB[0]) >>> 1; + case NORTHEAST: + return (bitboard & ~Bitboard.fileBB[7]) << 9; + case NORTHWEST: + return (bitboard & ~Bitboard.fileBB[0]) << 7; + case SOUTHEAST: + return (bitboard & ~Bitboard.fileBB[7]) >>> 7; + case SOUTHWEST: + return (bitboard & ~Bitboard.fileBB[0]) >>> 9; + } + + return bitboard; + } + + private static long generateKnightAttacks(Square square) + { + long attacks = 0L; + long squareBB = square.getBitboard(); + + attacks |= shift(shift(squareBB, Direction.NORTH), Direction.NORTHEAST); + attacks |= shift(shift(squareBB, Direction.NORTH), Direction.NORTHWEST); + attacks |= shift(shift(squareBB, Direction.SOUTH), Direction.SOUTHEAST); + attacks |= shift(shift(squareBB, Direction.SOUTH), Direction.SOUTHWEST); + attacks |= shift(shift(squareBB, Direction.EAST), Direction.NORTHEAST); + attacks |= shift(shift(squareBB, Direction.EAST), Direction.SOUTHEAST); + attacks |= shift(shift(squareBB, Direction.WEST), Direction.NORTHWEST); + attacks |= shift(shift(squareBB, Direction.WEST), Direction.SOUTHWEST); + + return attacks; + } + + private static long generateKingAttacks(Square square) + { + long attacks = 0L; + long squareBB = square.getBitboard(); + + attacks |= shift(squareBB, Direction.NORTH); + attacks |= shift(squareBB, Direction.SOUTH); + attacks |= shift(squareBB, Direction.EAST); + attacks |= shift(squareBB, Direction.WEST); + attacks |= shift(squareBB, Direction.NORTHEAST); + attacks |= shift(squareBB, Direction.NORTHWEST); + attacks |= shift(squareBB, Direction.SOUTHEAST); + attacks |= shift(squareBB, Direction.SOUTHWEST); + + return attacks; + } + + private static long generateRayMask(Square square, Direction direction) + { + long mask = 0L; + long sqBB = square.getBitboard(); + long nextBB = shift(sqBB, direction); + + while (true) + { + sqBB = nextBB; + nextBB = shift(sqBB, direction); + + if (0L == nextBB) + { + break; + } + + mask |= sqBB; + } + + return mask; + } + + private static long generateBishopMask(Square square) + { + long mask = 0L; + + mask |= generateRayMask(square, Direction.NORTHEAST); + mask |= generateRayMask(square, Direction.NORTHWEST); + mask |= generateRayMask(square, Direction.SOUTHEAST); + mask |= generateRayMask(square, Direction.SOUTHWEST); + + return mask; + } + + private static long generateRookMask(Square square) + { + long mask = 0L; + + mask |= generateRayMask(square, Direction.NORTH); + mask |= generateRayMask(square, Direction.SOUTH); + mask |= generateRayMask(square, Direction.EAST); + mask |= generateRayMask(square, Direction.WEST); + + return mask; + } + + private static int generateMagicShift(long mask) + { + return 64 - Long.bitCount(mask); + } + + private static long generateRayAttack(Square square, Direction direction, long occ) + { + long attack = 0L; + long sqBB = square.getBitboard(); + + while (true) + { + sqBB = shift(sqBB, direction); + attack |= sqBB; + + if (sqBB == 0 || 0L != (attack & occ)) + { + break; + } + } + + return attack; + } + + private static long generateBishopAttack(Square square, long occ) + { + long attack = 0L; + + attack |= generateRayAttack(square, Direction.NORTHEAST, occ); + attack |= generateRayAttack(square, Direction.NORTHWEST, occ); + attack |= generateRayAttack(square, Direction.SOUTHEAST, occ); + attack |= generateRayAttack(square, Direction.SOUTHWEST, occ); + + return attack; + } + + private static long generateRookAttack(Square square, long occ) + { + long attack = 0L; + + attack |= generateRayAttack(square, Direction.NORTH, occ); + attack |= generateRayAttack(square, Direction.SOUTH, occ); + attack |= generateRayAttack(square, Direction.EAST, occ); + attack |= generateRayAttack(square, Direction.WEST, occ); + + return attack; + } + + private static long[] generateBishopAttacks(Square square, long mask, long magic, int shift) + { + long[] attacks = new long[512]; + long cur_mask = mask; + + while (true) + { + attacks[(int) (cur_mask * magic >>> shift)] = generateBishopAttack(square, cur_mask); + + if (0L == cur_mask) + { + break; + } + + cur_mask = (cur_mask - 1) & mask; + } + + return attacks; + } + + private static long[] generateRookAttacks(Square square, long mask, long magic, int shift) + { + long[] attacks = new long[4096]; + long cur_mask = mask; + + while (true) + { + attacks[(int) (cur_mask * magic >>> shift)] = generateRookAttack(square, cur_mask); + + if (0L == cur_mask) + { + break; + } + + cur_mask = (cur_mask - 1) & mask; + } + + return attacks; + } + + /** + * Returns the bitboard representing the squares attacked by pawns placed on a + * set of locations for a given side. + * + * @param side the side to move + * @param pawnBB the bitboard of pawns + * @return the bitboard of the squares attacked by the pawn + */ + public static long getPawnAttacks(Side side, long pawnBB) + { + if (side.equals(Side.WHITE)) + { + return shift(pawnBB, Direction.NORTHEAST) | shift(pawnBB, Direction.NORTHWEST); + } + + else + { + return shift(pawnBB, Direction.SOUTHEAST) | shift(pawnBB, Direction.SOUTHWEST); + } + } + + /** + * Returns the bitboard representing the possible captures by a pawn placed on + * the input square for a given side. The method expects a bitboard of possible + * targets, the occupied squares, and the square for which en passant is + * playable ({@link Square#NONE} if en passant can not be played). + * + * @param side the side to move + * @param square the square the pawn is placed + * @param occupied a bitboard of possible targets + * @param enPassant the square in which en passant capture is possible, + * {@link Square#NONE} otherwise + * @return the bitboard of the squares where the pawn can move to capturing a + * piece + */ + public static long getPawnCaptures(Side side, long pawnBB, long occupied, Square enPassant) + { + long pawnAttacks = getPawnAttacks(side, pawnBB); + + if (!enPassant.equals(Square.NONE)) + { + long ep = enPassant.getBitboard(); + occupied |= side.equals(Side.WHITE) ? ep << 8L : ep >> 8L; + } + + return pawnAttacks & occupied; + } + + /** + * Returns the bitboard representing the possible moves, excluding captures, by + * a pawn placed on the input square for a given side. The method expects a + * bitboard of occupied squares where the pawn can not move to. + * + * @param side the side to move + * @param square the square the pawn is placed + * @param occupied a bitboard of occupied squares + * @return the bitboard of the squares where the pawn can move to + */ + public static long getPawnMoves(Side side, long pawnBB, long occupied) + { + Direction pushDirection = side.equals(Side.WHITE) ? Direction.NORTH : Direction.SOUTH; + final long doublePushMask = side.equals(Side.WHITE) ? Bitboard.rankBB[3] : Bitboard.rankBB[4]; + + final long pawnPushes = shift(pawnBB, pushDirection) & ~occupied; + final long pawnDoublePushes = shift(pawnPushes, pushDirection) & doublePushMask & ~occupied; + + return pawnPushes | pawnDoublePushes; + } + + /** + * Returns the bitboard representing the knight movement attacks, computed + * applying the provided mask. It could either refer to the squares attacked by + * a knight placed on the input square, or conversely the knights that can + * attack the square. + * + * @param square the square for which to calculate the knight attacks + * @param mask the mask to apply to the knight attacks + * @return the bitboard of knight movement attacks + */ + public static long getKnightAttacks(Square square, long mask) + { + return knightAttacks[square.ordinal()] & mask; + } + + /** + * Returns the bitboard representing the bishop movement attacks, computed + * applying the provided mask. It could either refer to the squares attacked by + * a bishop placed on the input square, or conversely the bishops that can + * attack the square. + * + * @param square the square for which to calculate the bishop attacks + * @param mask the mask to apply to the bishop attacks + * @return the bitboard of bishop movement attacks + */ + public static long getBishopAttacks(long mask, Square square) + { + long blockerMask = bishopMask[square.ordinal()]; + long magic = bishopMagic[square.ordinal()]; + int shift = bishopShift[square.ordinal()]; + + return bishopAttacks[square.ordinal()][(int) ((mask & blockerMask) * magic >>> shift)]; + } + + /** + * Returns the bitboard representing the rook movement attacks, computed + * applying the provided mask. It could either refer to the squares attacked by + * a rook placed on the input square, or conversely the rooks that can attack + * the square. + * + * @param square the square for which to calculate the rook attacks + * @param mask the mask to apply to the rook attacks + * @return the bitboard of rook movement attacks + */ + public static long getRookAttacks(long mask, Square square) + { + long blockerMask = rookMask[square.ordinal()]; + long magic = rookMagic[square.ordinal()]; + int shift = rookShift[square.ordinal()]; + + return rookAttacks[square.ordinal()][(int) ((mask & blockerMask) * magic >>> shift)]; + } + + /** + * Returns the bitboard representing the queen movement attacks, computed + * applying the provided mask. It could either refer to the squares attacked by + * a queen placed on the input square, or conversely the queens that can attack + * the square. + * + * @param square the square for which to calculate the queen attacks + * @param mask the mask to apply to the queen attacks + * @return the bitboard of queen movement attacks + */ + public static long getQueenAttacks(long mask, Square square) + { + return getRookAttacks(mask, square) | getBishopAttacks(mask, square); + } + + /** + * Returns the bitboard representing the king movement attacks, computed + * applying the provided mask. It could either refer to the squares attacked by + * a king placed on the input square, or conversely the kings that can attack + * the square. + * + * @param square the square for which to calculate the king attacks + * @param mask the mask to apply to the king attacks + * @return the bitboard of king movement attacks + */ + public static long getKingAttacks(Square square, long mask) + { + return kingAttacks[square.ordinal()] & mask; + } + + private class Precomputed + { + private static final long[] bishopMagic = { // + 0x0808431002060060L, 0x0010420214086902L, 0x0004211401000114L, 0x02060a1200005290L, // + 0x8012021000400000L, 0x0801015840800080L, 0x0004120804044500L, 0x0501040184240604L, // + 0x0a00682310020601L, 0x4001041002004901L, 0x6804500102002464L, 0x4800022082014400L, // + 0x00000a0210800008L, 0x0280c088044041b0L, 0x84000044100c1080L, 0x24101888c8021002L, // + 0x2008080451540810L, 0x0004080801080208L, 0xc0021a4400620200L, 0x0098000082004400L, // + 0x800e10c401040400L, 0x0420400809101021L, 0x0052000101901401L, 0x2001820032011000L, // + 0x0002109662604a03L, 0x0738580002100104L, 0x04030400018c0400L, 0x0001802108020020L, // + 0x0089001021014000L, 0x4000820001010080L, 0x880401406c064200L, 0x100202000c84c14dL, // + 0x0021211080200400L, 0x0108041010020200L, 0x000c004800011200L, 0x0280401048060200L, // + 0x0102008400220020L, 0x4022080200004050L, 0x0122008401050402L, 0x0014040150812100L, // + 0x0582020240212000L, 0x0218a80402031000L, 0x0101420041001020L, 0x0020902024200800L, // + 0x0800401093021202L, 0x00a2100202020020L, 0x1120640421408080L, 0x00888084008054c8L, // + 0x0004120804044500L, 0x1240908090102005L, 0x8000226884100400L, 0x0880008042020000L, // + 0x2000040410442040L, 0x041010200169002aL, 0x0808431002060060L, 0x0010420214086902L, // + 0x0501040184240604L, 0x24101888c8021002L, 0x6003250104431002L, 0x8012a0040c208801L, // + 0x0108041010020200L, 0x0400000420440100L, 0x0a00682310020601L, 0x0808431002060060L, }; + + private static final long[] rookMagic = { // + 0x0080004008811020L, 0x4840004020021009L, 0x5900130060004028L, 0xa480100080050801L, // + 0x1900100800050002L, 0xa400a00802040010L, 0x4100010020920024L, 0x1080002100005c80L, // + 0x0002800840028020L, 0x0000402000401000L, 0x0000808010002000L, 0x202200401a011020L, // + 0x0021001048010204L, 0x0001000844004300L, 0x0201000402000100L, 0x0c01800100004080L, // + 0x001c808004400220L, 0x0060810021024001L, 0x0020030040102101L, 0x0040808010030800L, // + 0x0078008048240080L, 0x400301001c004618L, 0x6400040006300108L, 0x00000a0000440081L, // + 0x0084400080028022L, 0x11005000c0002001L, 0x2410001080200080L, 0x00010029001000a4L, // + 0x8008080080040080L, 0x0402008080140026L, 0x00080c0101000200L, 0x6800006600010884L, // + 0x400840042080008aL, 0x2081a00080804008L, 0x0400504105002000L, 0x4022214202001048L, // + 0x0281800402800801L, 0x0002804401800600L, 0x0200b0018c000248L, 0x0800010062000094L, // + 0x0084400080028022L, 0x0001600050014000L, 0x400200c0208a0010L, 0x400200c0208a0010L, // + 0x0002006810060020L, 0x10860008101a0005L, 0x1482980302040050L, 0x000ca41680420001L, // + 0x8002409600630200L, 0x8002409600630200L, 0x2280460410208200L, 0x0010608810010100L, // + 0x8008080080040080L, 0x0001000844004300L, 0x0201000402000100L, 0x4080008244051600L, // + 0x0020210041108005L, 0x8009400021001281L, 0x0100a230802a00c2L, 0x11c2004008200432L, // + 0x402100020410c801L, 0x0112001001082452L, 0x6802101148820804L, 0x9028840023811042L, }; + + } +} \ No newline at end of file diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Bitboard.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Bitboard.java new file mode 100644 index 0000000..66c5055 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Bitboard.java @@ -0,0 +1,304 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import java.util.LinkedList; +import java.util.List; + +/** + * A collection of bitboards and related constant values useful to perform + * efficient board manipulations, fast squares comparisons, and to mask some + * operations to limited portions of the board. + *

+ * A bitboard is a specialized bit array data structure used in chess + * programming, where each bit corresponds to some binary information stored in + * a board (e.g. the presence of a piece, the property of a square, etc.). Given + * chessboards have 64 squares, bitboards can be represented by 64-bits numbers + * (long unsigned integer values). Data manipulation and comparison of different + * bitboards can be performed using bitwise operations. + */ +public class Bitboard +{ + /** + * The bitboard representing the light squares on a chessboard. + */ + public static final long lightSquares = 0x55AA55AA55AA55AAL; + /** + * The bitboard representing the dark squares on a chessboard. + */ + public static final long darkSquares = 0xAA55AA55AA55AA55L; + + /** + * The bitboards representing the ranks on a chessboard. Bitboard at index 0 + * identifies the 1st rank on a board, bitboard at index 1 the 2nd rank, etc. + */ + final static long[] rankBB = { 0x00000000000000FFL, 0x000000000000FF00L, 0x0000000000FF0000L, 0x00000000FF000000L, + 0x000000FF00000000L, 0x0000FF0000000000L, 0x00FF000000000000L, 0xFF00000000000000L }; + /** + * The bitboards representing the files on a chessboard. Bitboard at index 0 + * identifies the 1st file on a board, bitboard at index 1 the 2nd file, etc. + */ + final static long[] fileBB = { 0x0101010101010101L, 0x0202020202020202L, 0x0404040404040404L, 0x0808080808080808L, + 0x1010101010101010L, 0x2020202020202020L, 0x4040404040404040L, 0x8080808080808080L }; + + /** + * Table of bitboards that represent portions of board included between two + * squares, specified by the indexes used to access the table. A portion of + * board is the two-dimensional space defined by the ranks and files of the + * squares. + *

+ * For instance, the bitboard looked up by coordinates {@code (0, 18)} defines + * the portion of the board included between squares {@code A1} and {@code C3} + * (indexes 0 and 18 respectively), i.e. the set of squares + * {@code [A1, B1, C1, A2, B2, C2, A3, B3, C3]}. + */ + final static long[][] bbTable = new long[64][64]; + + static + { + for (int x = 0; x < 64; x++) + { + for (int y = 0; y < 64; y++) + { + bbTable[x][y] = ((1L << y) | ((1L << y) - (1L << x))); + } + } + } + + /** + * Returns the bitboard representing the single square provided in input. + * + * @param sq the square for which the bitboard must be returned + * @return the bitboard representation of the square + */ + static long sq2Bb(Square sq) + { + return sq.getBitboard(); + } + + /** + * Returns the index of the first (rightmost) bit set to 1 in the + * bitboard provided in input. The bit is the Least Significant 1-bit (LS1B). + * + * @param bb the bitboard for which the LS1B is to be returned + * @return the index of the first bit set to 1 + */ + public static int bitScanForward(long bb) + { + return Long.numberOfTrailingZeros(bb); + } + + /** + * Returns the index of the last (leftmost) bit set to 1 in the bitboard + * provided in input. The bit is the Most Significant 1-bit (MS1B). + * + * @param bb the bitboard for which the MS1B is to be returned + * @return the index of the last bit set to 1 + */ + public static int bitScanReverse(long bb) + { + return 63 - Long.numberOfLeadingZeros(bb); + } + + /** + * Returns the sub-bitboard included between the two squares provided in + * input, that is, the portion of the bitboard included between two squares. The + * sub-bitboard is a two-dimensional space defined by the ranks and files + * of the two squares. For example, if squares {@code A1} and {@code C3} are + * provided in input, the method returns only the following squares of the + * original bitboard: {@code [A1, B1, C1, A2, B2, C2, A3, B3, C3]}. All other + * bits are set to 0. + * + * @param bb the bitboard the portion between the two squares must be returned + * @param sq1 the first square that defines the two-dimensional space + * @param sq2 the second square that defines the two-dimensional space + * @return the portion of the original bitboard included between the two squares + */ + public static long bitsBetween(long bb, int sq1, int sq2) + { + return bbTable[sq1][sq2] & bb; + } + + /** + * Unsets the first bit set to 1. In other words, it sets to 0 the Least + * Significant 1-bit (LS1B). + * + * @param bb the bitboard to compute + * @return the resulting bitboard, from which the first bit set to 1 has been + * unset + */ + public static long extractLsb(Long bb) + { + return bb & (bb - 1); + } + + /** + * Check whether the given bitboard has only one bit set to 1. + * + * @param bb the bitboard to check + * @return {@code true} if the bitboard has only one bit set to 1 + */ + public static boolean hasOnly1Bit(Long bb) + { + return bb != 0L && extractLsb(bb) == 0L; + } + + /** + * Returns the bitboard representing the square provided in input. + * + * @param sq the square for which the bitboard must be returned + * @return the bitboard representing the single square + */ + public static long getBbtable(Square sq) + { + return 1L << sq.ordinal(); + } + + /** + * Returns the list of squares that are set in the bitboard provided in input, + * that is, the squares corresponding to the indexes set to 1 in the bitboard. + * + * @param bb the bitboard from which the list of squares must be returned + * @return the list of squares corresponding to the bits set to 1 in the + * bitboard + */ + public static List bbToSquareList(long bb) + { + List squares = new LinkedList(); + while (bb != 0L) + { + int sq = Bitboard.bitScanForward(bb); + bb = Bitboard.extractLsb(bb); + squares.add(Square.squareAt(sq)); + } + return squares; + } + + /** + * Returns the array of squares that are set in the bitboard provided in input, + * that is, the squares corresponding to the indexes set to 1 in the bitboard. + * + * @param bb the bitboard from which the array of squares must be returned + * @return the array of squares corresponding to the bits set to 1 in the + * bitboard + */ + public static Square[] bbToSquareArray(long bb) + { + Square[] squares = new Square[Long.bitCount(bb)]; + int index = 0; + while (bb != 0L) + { + int sq = bitScanForward(bb); + bb = extractLsb(bb); + squares[index++] = Square.squareAt(sq); + } + return squares; + } + + /** + * Returns the bitboards representing the ranks on a chessboard. + * + * @return the bitboards representing the ranks + */ + public static long[] getRankbb() + { + return rankBB; + } + + /** + * Returns the bitboards representing the files on a chessboard. + * + * @return the bitboards representing the files + */ + public static long[] getFilebb() + { + return fileBB; + } + + /** + * Returns the bitboard representing the entire rank of the square given in + * input. + * + * @param sq the square for which the bitboard rank must be returned + * @return the bitboards representing the rank of the square + */ + public static long getRankbb(Square sq) + { + return rankBB[sq.getRank().ordinal()]; + } + + /** + * Returns the bitboard representing the entire file of the square given in + * input. + * + * @param sq the square for which the bitboard file must be returned + * @return the bitboards representing the file of the square + */ + public static long getFilebb(Square sq) + { + return fileBB[sq.getFile().ordinal()]; + } + + /** + * Returns the bitboard representing the rank given in input. + * + * @param rank the rank for which the corresponding bitboard must be returned + * @return the bitboards representing the rank + */ + public static long getRankbb(Rank rank) + { + return rankBB[rank.ordinal()]; + } + + /** + * Returns the bitboard representing the file given in input. + * + * @param file the file for which the corresponding bitboard must be returned + * @return the bitboards representing the file + */ + public static long getFilebb(File file) + { + return fileBB[file.ordinal()]; + } + + /** + * Returns the string representation of a bitboard in a readable format. + * + * @param bb the bitboard to print + * @return the string representation of the bitboard + */ + public static String bitboardToString(long bb) + { + StringBuilder b = new StringBuilder(); + for (int x = 0; x < 64; x++) + { + if (((1L << x) & bb) != 0L) + { + b.append("1"); + } + else + { + b.append("0"); + } + if ((x + 1) % 8 == 0) + { + b.append("\n"); + } + } + return b.toString(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Board.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Board.java new file mode 100644 index 0000000..855df74 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Board.java @@ -0,0 +1,2565 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import static org.shawn.games.Serendipity.Chess.Bitboard.extractLsb; +import static org.shawn.games.Serendipity.Chess.Constants.emptyMove; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +import org.shawn.games.Serendipity.Chess.move.Move; +import org.shawn.games.Serendipity.Chess.move.MoveGenerator; +import org.shawn.games.Serendipity.Chess.move.MoveList; +import org.shawn.games.Serendipity.Chess.util.XorShiftRandom; +import org.apache.commons.lang3.StringUtils; + +/** + * The definition of a chessboard position and its status. It exposes methods to + * manipulate the board, evolve the position moving pieces around, revert + * already performed moves, and retrieve the status of the current configuration + * on the board. Furthermore, it offers a handy way for loading a position from + * a Forsyth-Edwards Notation (FEN) string and exporting it in the same format. + *

+ * Each position in uniquely identified by hashes that could be retrieved using + * {@link Board#getIncrementalHashKey()} and {@link Board#getZobristKey()} + * methods. Also, the implementation supports comparison against other board + * instances using either the strict ({@link Board#strictEquals(Object)}) or the + * non-strict ({@link Board#equals(Object)}) mode. + *

+ * The board can be observed registering {@link BoardEventListener}s for + * particular types of events. Moreover, the {@link Board} class itself is a + * {@link BoardEvent}, and hence it can be passed to the observers of the + * {@link BoardEventType#ON_LOAD} events, emitted when a new chess position is + * loaded from an external source (e.g. a FEN string). + */ +public class Board implements Cloneable +{ + + private static final List keys = new ArrayList<>(); + private static final long RANDOM_SEED = 49109794719L; + private static final int ZOBRIST_TABLE_SIZE = 2000; + + static + { + final XorShiftRandom random = new XorShiftRandom(RANDOM_SEED); + for (int i = 0; i < ZOBRIST_TABLE_SIZE; i++) + { + long key = random.nextLong(); + keys.add(key); + } + } + + private final LinkedList backup; + private final long[] bitboard; + private final long[] bbSide; + private final Piece[] occupation; + private final EnumMap castleRight; + private final LinkedList history = new LinkedList<>(); + private Side sideToMove; + private Square enPassantTarget; + private Square enPassant; + private Integer moveCounter; + private Integer halfMoveCounter; + private BoardContext context; + private boolean enableEvents; + private final boolean updateHistory; + private long incrementalHashKey; + + /** + * Constructs a new board using a default game context. The board will keep its + * history updated, that is, will store a hash value for each position + * encountered. + * + * @see Board#Board(BoardContext, boolean) + */ + public Board() + { + this(new BoardContext(), true); + } + + /** + * Constructs a new board, using the game context provided in input. When + * history updates are enabled, the board will keep the hashes of all positions + * encountered. + * + * @param gameContext the game context to use for this board + * @param updateHistory whether to keep the history updated or not + */ + public Board(BoardContext gameContext, boolean updateHistory) + { + bitboard = new long[Piece.allPieces.length]; + bbSide = new long[Side.allSides.length]; + occupation = new Piece[Square.values().length]; + castleRight = new EnumMap<>(Side.class); + backup = new LinkedList<>(); + context = gameContext; + this.updateHistory = updateHistory; + setSideToMove(Side.WHITE); + setEnPassantTarget(Square.NONE); + setEnPassant(Square.NONE); + setMoveCounter(1); + setHalfMoveCounter(0); + loadFromFen(gameContext.getStartFEN()); + setEnableEvents(true); + } + + /* + * does move lead to a promotion? + */ + private static boolean isPromoRank(Side side, Move move) + { + if (side.equals(Side.WHITE) && move.getTo().getRank().equals(Rank.RANK_8)) + { + return true; + } + else + return side.equals(Side.BLACK) && move.getTo().getRank().equals(Rank.RANK_1); + + } + + private static Square findEnPassantTarget(Square sq, Side side) + { + Square ep = Square.NONE; + if (!Square.NONE.equals(sq)) + { + ep = Side.WHITE.equals(side) ? Square.encode(Rank.RANK_5, sq.getFile()) + : Square.encode(Rank.RANK_4, sq.getFile()); + } + return ep; + } + + private static Square findEnPassant(Square sq, Side side) + { + Square ep = Square.NONE; + if (!Square.NONE.equals(sq)) + { + ep = Side.WHITE.equals(side) ? Square.encode(Rank.RANK_3, sq.getFile()) + : Square.encode(Rank.RANK_6, sq.getFile()); + } + return ep; + } + + private static IntStream zeroToSeven() + { + return IntStream.iterate(0, i -> i + 1).limit(8); + } + + private static IntStream sevenToZero() + { + return IntStream.iterate(7, i -> i - 1).limit(8); + } + + /** + * Executes a move on the board, specified in Short Algebraic Notation (SAN). + * + * @param move the move to execute in SAN notation, such as {@code Nc3} + */ + public void doMove(final String move) + { + MoveList moves = new MoveList(this.getFen()); + moves.addSanMove(move, true, true); + doMove(moves.removeLast()); + } + + /** + * Executes a move on the board. It returns {@code true} if the operation has + * been successful and the position changed after the move. When a full + * validation is requested, additional checks are performed to assess the + * outcome of the operation, such as if the side to move is the expected one, if + * castling or promotion moves are allowed, if the move replaces another piece + * of the same side, etc. + *

+ * N.B.: the method does not check whether the move is legal or not + * according to the standard chess rules, but rather if the resulting + * configuration is valid. For instance, it is totally fine to move the king by + * two or more squares, or a rook beyond its friendly pieces, as long as the + * position obtained after the move does not violate any chess constraint. + * + * @param move the move to execute + * @return the changes to be applied onto the accumulator + */ + public AccumulatorDiff doMove(final Move move) + { + assert isMoveLegal(move, true); + assert isMovePseudoLegal(move); + + AccumulatorDiff diff = new AccumulatorDiff(); + Piece movingPiece = getPiece(move.getFrom()); + Side side = getSideToMove(); + + MoveBackup backupMove = new MoveBackup(this, move); + final boolean isCastle = context.isCastleMove(move); + + incrementalHashKey ^= getSideKey(getSideToMove()); + + if (getEnPassantTarget() != Square.NONE) + { + incrementalHashKey ^= getEnPassantKey(getEnPassantTarget()); + } + + diff.removePiece(movingPiece, move.getFrom()); + + if (move.isPromotion()) + { + diff.addPiece(move.getPromotion(), move.getTo()); + } + else + { + diff.addPiece(movingPiece, move.getTo()); + } + + if (PieceType.KING.equals(movingPiece.getPieceType())) + { + if (isCastle) + { + assert context.hasCastleRight(move, getCastleRight(side)); + + CastleRight c = context.isKingSideCastle(move) ? CastleRight.KING_SIDE : CastleRight.QUEEN_SIDE; + Move rookMove = context.getRookCastleMove(side, c); + diff.removePiece(Piece.make(side, PieceType.ROOK), rookMove.getFrom()); + diff.addPiece(Piece.make(side, PieceType.ROOK), rookMove.getTo()); + movePiece(rookMove, backupMove); + } + + if (getCastleRight(side) != CastleRight.NONE) + { + incrementalHashKey ^= getCastleRightKey(side); + getCastleRight().put(side, CastleRight.NONE); + } + } + + else if (PieceType.ROOK == movingPiece.getPieceType() && CastleRight.NONE != getCastleRight(side)) + { + final Move oo = context.getRookoo(side); + final Move ooo = context.getRookooo(side); + + if (move.getFrom() == oo.getFrom()) + { + if (CastleRight.KING_AND_QUEEN_SIDE == getCastleRight(side)) + { + incrementalHashKey ^= getCastleRightKey(side); + getCastleRight().put(side, CastleRight.QUEEN_SIDE); + incrementalHashKey ^= getCastleRightKey(side); + } + else if (CastleRight.KING_SIDE == getCastleRight(side)) + { + incrementalHashKey ^= getCastleRightKey(side); + getCastleRight().put(side, CastleRight.NONE); + } + } + else if (move.getFrom() == ooo.getFrom()) + { + if (CastleRight.KING_AND_QUEEN_SIDE == getCastleRight(side)) + { + incrementalHashKey ^= getCastleRightKey(side); + getCastleRight().put(side, CastleRight.KING_SIDE); + incrementalHashKey ^= getCastleRightKey(side); + } + else if (CastleRight.QUEEN_SIDE == getCastleRight(side)) + { + incrementalHashKey ^= getCastleRightKey(side); + getCastleRight().put(side, CastleRight.NONE); + } + } + } + + Piece capturedPiece = movePiece(move, backupMove); + + if (!Piece.NONE.equals(capturedPiece)) + { + Square captureSquare = move.getTo(); + + if (movingPiece.getPieceType().equals(PieceType.PAWN) && move.getTo() == getEnPassant()) + { + captureSquare = getEnPassantTarget(); + } + + diff.removePiece(capturedPiece, captureSquare); + } + + if (PieceType.ROOK == capturedPiece.getPieceType()) + { + final Move oo = context.getRookoo(side.flip()); + final Move ooo = context.getRookooo(side.flip()); + + if (move.getTo() == oo.getFrom()) + { + if (CastleRight.KING_AND_QUEEN_SIDE == getCastleRight(side.flip())) + { + incrementalHashKey ^= getCastleRightKey(side.flip()); + getCastleRight().put(side.flip(), CastleRight.QUEEN_SIDE); + incrementalHashKey ^= getCastleRightKey(side.flip()); + } + + else if (CastleRight.KING_SIDE == getCastleRight(side.flip())) + { + incrementalHashKey ^= getCastleRightKey(side.flip()); + getCastleRight().put(side.flip(), CastleRight.NONE); + } + } + + else if (move.getTo() == ooo.getFrom()) + { + if (CastleRight.KING_AND_QUEEN_SIDE == getCastleRight(side.flip())) + { + incrementalHashKey ^= getCastleRightKey(side.flip()); + getCastleRight().put(side.flip(), CastleRight.KING_SIDE); + incrementalHashKey ^= getCastleRightKey(side.flip()); + } + + else if (CastleRight.QUEEN_SIDE == getCastleRight(side.flip())) + { + incrementalHashKey ^= getCastleRightKey(side.flip()); + getCastleRight().put(side.flip(), CastleRight.NONE); + } + } + } + + if (Piece.NONE == capturedPiece) + { + setHalfMoveCounter(getHalfMoveCounter() + 1); + } + + else + { + setHalfMoveCounter(0); + } + + setEnPassantTarget(Square.NONE); + setEnPassant(Square.NONE); + + if (PieceType.PAWN == movingPiece.getPieceType()) + { + if (Math.abs(move.getTo().getRank().ordinal() - move.getFrom().getRank().ordinal()) == 2) + { + Piece otherPawn = Piece.make(side.flip(), PieceType.PAWN); + setEnPassant(findEnPassant(move.getTo(), side)); + + if (hasPiece(otherPawn, move.getTo().getSideSquares()) + && verifyNotPinnedPiece(side, getEnPassant(), move.getTo())) + { + setEnPassantTarget(move.getTo()); + incrementalHashKey ^= getEnPassantKey(getEnPassantTarget()); + } + } + + setHalfMoveCounter(0); + } + + if (side == Side.BLACK) + { + setMoveCounter(getMoveCounter() + 1); + } + + setSideToMove(side.flip()); + incrementalHashKey ^= getSideKey(getSideToMove()); + + if (updateHistory) + { + getHistory().addLast(getIncrementalHashKey()); + } + + backup.add(backupMove); + + return diff; + } + + /** + * Executes a null move on the board. It returns {@code true} if the + * operation has been successful. + *

+ * A null move it is a special move that does not change the position of any + * piece, but simply updates the history of the board and switches the side to + * move. It could be useful in some scenarios to implement a "passing + * turn" behavior. + * + * @return {@code true} if the null move was successful + */ + public boolean doNullMove() + { + Side side = getSideToMove(); + MoveBackup backupMove = new MoveBackup(this, emptyMove); + + setHalfMoveCounter(getHalfMoveCounter() + 1); + + setEnPassantTarget(Square.NONE); + setEnPassant(Square.NONE); + + incrementalHashKey ^= getSideKey(getSideToMove()); + setSideToMove(side.flip()); + incrementalHashKey ^= getSideKey(getSideToMove()); + + if (updateHistory) + { + getHistory().addLast(getIncrementalHashKey()); + } + + backup.add(backupMove); + return true; + } + + /** + * Reverts the latest move played on the board and returns it. If no moves were + * previously executed, it returns null. + * + * @return the reverted move, or null if no previous moves were played + */ + public Move undoMove() + { + Move move = null; + final MoveBackup b = backup.removeLast(); + + if (updateHistory) + { + getHistory().removeLast(); + } + + if (b != null) + { + move = b.getMove(); + b.restore(this); + } + + return move; + } + + /** + * Moves a piece on the board and updates the backup passed in input. It returns + * the captured piece, if any, or {@link Piece#NONE} otherwise. + *

+ * Same as invoking + * {@code movePiece(move.getFrom(), move.getTo(), move.getPromotion(), backup)}. + * + * @param move the move to perform + * @param backup the move backup to update + * @return the captured piece, if present, or {@link Piece#NONE} otherwise + * @see Board#movePiece(Square, Square, Piece, MoveBackup) + */ + protected Piece movePiece(Move move, MoveBackup backup) + { + return movePiece(move.getFrom(), move.getTo(), move.getPromotion(), backup); + } + + /** + * Moves a piece on the board and updates the backup passed in input. It returns + * the captured piece, if any, or {@link Piece#NONE} otherwise. The piece + * movement is described by its starting and destination squares, and by the + * piece to promote the moving piece to in case of a promotion. + * + * @param from the starting square of the piece + * @param to the destination square of the piece + * @param promotion the piece to set on the board to replace the moving piece + * after its promotion, or {@link Piece#NONE} in case the move + * is not a promotion + * @param backup the move backup to update + * @return the captured piece, if present, or {@link Piece#NONE} otherwise + */ + protected Piece movePiece(Square from, Square to, Piece promotion, MoveBackup backup) + { + Piece movingPiece = getPiece(from); + Piece capturedPiece = getPiece(to); + + unsetPiece(movingPiece, from); + + if (!Piece.NONE.equals(capturedPiece)) + { + unsetPiece(capturedPiece, to); + } + + if (!Piece.NONE.equals(promotion)) + { + setPiece(promotion, to); + } + + else + { + setPiece(movingPiece, to); + } + + if (PieceType.PAWN.equals(movingPiece.getPieceType()) && !Square.NONE.equals(getEnPassantTarget()) + && !to.getFile().equals(from.getFile()) && Piece.NONE.equals(capturedPiece)) + { + capturedPiece = getPiece(getEnPassantTarget()); + if (backup != null && !Piece.NONE.equals(capturedPiece)) + { + unsetPiece(capturedPiece, getEnPassantTarget()); + backup.setCapturedSquare(getEnPassantTarget()); + backup.setCapturedPiece(capturedPiece); + } + } + return capturedPiece; + } + + /** + * Reverts the effects of a piece previously moved. It restores the moved piece + * where it was and cancels any possible promotion to another piece. + * + * @param move the move to undo + */ + protected void undoMovePiece(Move move) + { + Square from = move.getFrom(); + Square to = move.getTo(); + Piece promotion = move.getPromotion(); + Piece movingPiece = getPiece(to); + + unsetPiece(movingPiece, to); + + if (!Piece.NONE.equals(promotion)) + { + setPiece(Piece.make(getSideToMove(), PieceType.PAWN), from); + } + else + { + setPiece(movingPiece, from); + } + } + + /** + * Searches the piece in any of the squares provided in input and returns + * {@code true} if found. + * + * @param piece the piece to search in any of the given squares + * @param location an array of squares where to look the piece for + * @return {@code true} if the piece is found + */ + public boolean hasPiece(Piece piece, Square[] location) + { + for (Square sq : location) + { + if ((getBitboard(piece) & sq.getBitboard()) != 0L) + { + return true; + } + } + return false; + } + + /** + * Returns the piece at the specified square, or {@link Piece#NONE} if the + * square is empty. + * + * @param sq the square to get the piece from + * @return the found piece, or {@link Piece#NONE} if no piece is present on the + * square + */ + public Piece getPiece(Square sq) + { + + return occupation[sq.ordinal()]; + } + + /** + * Returns the bitboard that represents all the pieces on the board, for both + * sides. + * + * @return the bitboard of all the pieces on the board + */ + public long getBitboard() + { + return bbSide[0] | bbSide[1]; + } + + /** + * Returns the bitboard that represents all the pieces of a given side and type + * present on the board. + * + * @param piece the piece for which the bitboard must be returned + * @return the bitboard of the given piece definition + */ + public long getBitboard(Piece piece) + { + return bitboard[piece.ordinal()]; + } + + /** + * Returns the bitboard that represents all the pieces of a given side and type + * present on the board. + * + * @param side the side for which the bitboard must be returned + * @param pieceType the piece type for which the bitboard must be returned + * @return the bitboard of the given piece definition + */ + public long getBitboard(Side side, PieceType pieceType) + { + return bitboard[Piece.make(side, pieceType).ordinal()]; + } + + /** + * Returns the bitboard that represents all the pieces of a given type present + * on the board. + * + * @param pieceType the piece type for which the bitboard must be returned + * @return the bitboard of the given piece definition + */ + public long getBitboard(PieceType pieceType) + { + return bitboard[Piece.make(Side.WHITE, pieceType).ordinal()] + | bitboard[Piece.make(Side.BLACK, pieceType).ordinal()]; + } + + /** + * Returns the bitboard that represents all the pieces of a given side present + * on the board. + * + * @param side the side for which the bitboard must be returned + * @return the bitboard of all the pieces of the side + */ + public long getBitboard(Side side) + { + return bbSide[side.ordinal()]; + } + + /** + * Returns the bitboards that represents all the pieces present on the board, + * one for each side. The bitboard for white is stored at index 0, the bitboard + * for black at index 1. + * + * @return the bitboards of all the pieces for both sides + */ + public long[] getBbSide() + { + return bbSide; + } + + /** + * Returns the list of squares that contain all the pieces of a given side and + * type. + * + * @param piece the piece for which the list of squares must be returned + * @return the list of squares that contain the given piece definition + */ + public List getPieceLocation(Piece piece) + { + if (getBitboard(piece) != 0L) + { + return Bitboard.bbToSquareList(getBitboard(piece)); + } + return Collections.emptyList(); + } + + /** + * Returns the square of the first piece of a given side and type found on the + * board, scanning from lower ranks/files. If no piece is found, + * {@link Square#NONE} is returned. + * + * @param piece the piece for which the first encountered square must be + * returned + * @return the first square that contain the given piece definition, or + * {@link Square#NONE} if the piece is not found + */ + public Square getFistPieceLocation(Piece piece) + { + if (getBitboard(piece) != 0L) + { + return Square.squareAt(Bitboard.bitScanForward(getBitboard(piece))); + } + return Square.NONE; + } + + /** + * Returns the next side to move. + * + * @return the next side to move + */ + public Side getSideToMove() + { + return sideToMove; + } + + /** + * Sets the next side to move. + * + * @param sideToMove the side to move to set + */ + public void setSideToMove(Side sideToMove) + { + this.sideToMove = sideToMove; + } + + /** + * Returns the target square of an en passant capture, if any. In other words, + * the square which contains the pawn that can be captured en passant. + * + * @return the en passant target square, or {@link Square#NONE} if en passant is + * not possible + * @see Board#getEnPassant() + */ + public Square getEnPassantTarget() + { + return enPassantTarget; + } + + /** + * Sets the en passant target square. + * + * @param enPassant the en passant target square to set + * @see Board#getEnPassantTarget() + */ + public void setEnPassantTarget(Square enPassant) + { + this.enPassantTarget = enPassant; + } + + /** + * Returns the destination square of an en passant capture, if any. In other + * words, the square a pawn will move to in case an enemy pawn is captured en + * passant. + * + * @return the en passant destination square, or {@link Square#NONE} if en + * passant is not possible + * @see Board#getEnPassantTarget() + */ + public Square getEnPassant() + { + return enPassant; + } + + /** + * Sets the en passant destination square. + * + * @param enPassant the en passant destination square to set + * @see Board#getEnPassant() + */ + public void setEnPassant(Square enPassant) + { + this.enPassant = enPassant; + } + + /** + * Returns the counter of full moves played. The counter is incremented after + * each move played by black. + * + * @return the counter of full moves + */ + public Integer getMoveCounter() + { + return moveCounter; + } + + /** + * Sets the counter of full moves. + * + * @param moveCounter the counter of full moves to set + * @see Board#getMoveCounter() + */ + public void setMoveCounter(Integer moveCounter) + { + this.moveCounter = moveCounter; + } + + /** + * Returns the counter of half moves. The counter is incremented after each + * capture or pawn move, and it is used to apply the fifty-move rule. + * + * @return the counter of half moves + */ + public Integer getHalfMoveCounter() + { + return halfMoveCounter; + } + + /** + * Sets the counter of half moves. + * + * @param halfMoveCounter the counter of half moves to set + * @see Board#getHalfMoveCounter() + */ + public void setHalfMoveCounter(Integer halfMoveCounter) + { + this.halfMoveCounter = halfMoveCounter; + } + + /** + * Returns the castle right of a given side. + * + * @param side the side for which the castle right must be returned + * @return the castle right of the side + */ + public CastleRight getCastleRight(Side side) + { + return castleRight.get(side); + } + + /** + * Returns the castle rights for both sides, stored in an {@link EnumMap}. + * + * @return the map containing the castle rights for both sides + */ + public EnumMap getCastleRight() + { + return castleRight; + } + + /** + * Returns the game context used for this board. + * + * @return the game context + */ + public BoardContext getContext() + { + return context; + } + + /** + * Sets the game context of the board. + * + * @param context the game context to set + */ + public void setContext(BoardContext context) + { + this.context = context; + } + + /** + * Returns the current ordered list of move backups generated from the moves + * performed on the board. + * + * @return the list of move backups + */ + public LinkedList getBackup() + { + return backup; + } + + /** + * Clears the entire board and resets its status and all the flags to their + * default value. + */ + public void clear() + { + setSideToMove(Side.WHITE); + setEnPassantTarget(Square.NONE); + setEnPassant(Square.NONE); + setMoveCounter(0); + setHalfMoveCounter(0); + getHistory().clear(); + + Arrays.fill(bitboard, 0L); + Arrays.fill(bbSide, 0L); + Arrays.fill(occupation, Piece.NONE); + backup.clear(); + incrementalHashKey = 0; + } + + /** + * Sets a piece on a square. + *

+ * The operation does not perform any move, but rather simply puts a piece onto + * a square. + * + * @param piece the piece to be placed on the square + * @param sq the square the piece has to be set to + */ + public void setPiece(Piece piece, Square sq) + { + bitboard[piece.ordinal()] |= sq.getBitboard(); + bbSide[piece.getPieceSide().ordinal()] |= sq.getBitboard(); + occupation[sq.ordinal()] = piece; + + if (piece != Piece.NONE && sq != Square.NONE) + { + incrementalHashKey ^= getPieceSquareKey(piece, sq); + } + } + + /** + * Unsets a piece from a square. + * + * @param piece the piece to be removed from the square + * @param sq the square the piece has to be unset from + */ + public void unsetPiece(Piece piece, Square sq) + { + bitboard[piece.ordinal()] ^= sq.getBitboard(); + bbSide[piece.getPieceSide().ordinal()] ^= sq.getBitboard(); + occupation[sq.ordinal()] = Piece.NONE; + + if (piece != Piece.NONE && sq != Square.NONE) + { + incrementalHashKey ^= getPieceSquareKey(piece, sq); + } + } + + /** + * Loads a specific chess position from a valid Forsyth-Edwards Notation (FEN) + * string. The status of the current board is replaced with the one of the FEN + * string (e.g. en passant squares, castle rights, etc.). + * + * @param fen the FEN string representing the chess position to load + */ + public void loadFromFen(String fen) + { + clear(); + String squares = fen.substring(0, fen.indexOf(' ')); + String state = fen.substring(fen.indexOf(' ') + 1); + + String[] ranks = squares.split("/"); + int file; + int rank = 7; + + for (String r : ranks) + { + file = 0; + for (int i = 0; i < r.length(); i++) + { + char c = r.charAt(i); + + if (Character.isDigit(c)) + { + file += Character.digit(c, 10); + } + + else + { + Square sq = Square.encode(Rank.allRanks[rank], File.allFiles[file]); + setPiece(Piece.fromFenSymbol(String.valueOf(c)), sq); + file++; + } + } + rank--; + } + + sideToMove = state.toLowerCase().charAt(0) == 'w' ? Side.WHITE : Side.BLACK; + + if (state.contains("KQ")) + { + castleRight.put(Side.WHITE, CastleRight.KING_AND_QUEEN_SIDE); + } + + else if (state.contains("K")) + { + castleRight.put(Side.WHITE, CastleRight.KING_SIDE); + } + + else if (state.contains("Q")) + { + castleRight.put(Side.WHITE, CastleRight.QUEEN_SIDE); + } + + else + { + castleRight.put(Side.WHITE, CastleRight.NONE); + } + + if (state.contains("kq")) + { + castleRight.put(Side.BLACK, CastleRight.KING_AND_QUEEN_SIDE); + } + + else if (state.contains("k")) + { + castleRight.put(Side.BLACK, CastleRight.KING_SIDE); + } + + else if (state.contains("q")) + { + castleRight.put(Side.BLACK, CastleRight.QUEEN_SIDE); + } + + else + { + castleRight.put(Side.BLACK, CastleRight.NONE); + } + + String[] flags = state.split(StringUtils.SPACE); + + if (flags.length >= 3) + { + String s = flags[2].toUpperCase().trim(); + + if (!s.equals("-")) + { + Square ep = Square.valueOf(s); + setEnPassant(ep); + setEnPassantTarget(findEnPassantTarget(ep, sideToMove)); + if (!pawnCanBeCapturedEnPassant()) + { + setEnPassantTarget(Square.NONE); + } + } + + else + { + setEnPassant(Square.NONE); + setEnPassantTarget(Square.NONE); + } + + if (flags.length >= 4) + { + halfMoveCounter = Integer.parseInt(flags[3]); + if (flags.length >= 5) + { + moveCounter = Integer.parseInt(flags[4]); + } + } + } + + incrementalHashKey = getZobristKey(); + + if (updateHistory) + { + getHistory().addLast(this.getZobristKey()); + } + } + + /** + * Generates the Forsyth-Edwards Notation (FEN) representation of the current + * position and its status. Full and half moves counters are included in the + * output. + *

+ * Same as invoking {@code getFen(true, false)}. + * + * @return the string that represents the current position in FEN notation + * @see Board#getFen(boolean, boolean) + */ + public String getFen() + { + return getFen(true); + } + + /** + * Generates the Forsyth-Edwards Notation (FEN) representation of the current + * position and its status. Full and half moves counters are included in the + * output if the relative flag is enabled. + *

+ * Same as invoking {@code getFen(includeCounters, false)}. + * + * @param includeCounters if {@code true}, move counters are included in the + * resulting string + * @return the string that represents the current position in FEN notation + * @see Board#getFen(boolean, boolean) + */ + public String getFen(boolean includeCounters) + { + return getFen(includeCounters, false); + } + + /** + * Generates the Forsyth-Edwards Notation (FEN) representation of the current + * position and its status. Full and half moves counters are included in the + * output if the relative flag is enabled. Furthermore, it is possible to + * control whether to include the en passant square in the result only when the + * pawn can be captured or every time the en passant target exists. + * + * @param includeCounters if {@code true}, move counters are + * included in the resulting string + * @param onlyOutputEnPassantIfCapturable if {@code true}, the en passant square + * is included in the output only if the + * pawn that just moved can be captured. + * Otherwise, if {@code false}, the en + * passant square is always included in + * the output when the en passant target + * exists + * @return the string that represents the current position in FEN notation + */ + public String getFen(boolean includeCounters, boolean onlyOutputEnPassantIfCapturable) + { + StringBuffer fen = new StringBuffer(); + int emptySquares = 0; + for (int i = 7; i >= 0; i--) + { + Rank r = Rank.allRanks[i]; + + if (r == Rank.NONE) + { + continue; + } + + for (File f : File.allFiles) + { + if (f == File.NONE) + { + continue; + } + + Square sq = Square.encode(r, f); + Piece piece = getPiece(sq); + + if (Piece.NONE.equals(piece)) + { + emptySquares++; + } + + else + { + if (emptySquares > 0) + { + fen.append(emptySquares); + emptySquares = 0; + } + + fen.append(piece.getFenSymbol()); + } + + if (f != File.FILE_H) + { + continue; + } + + if (emptySquares > 0) + { + fen.append(emptySquares); + emptySquares = 0; + } + + if (r != Rank.RANK_1) + { + fen.append("/"); + } + } + } + + if (Side.WHITE.equals(sideToMove)) + { + fen.append(" w"); + } + else + { + fen.append(" b"); + } + + String rights = StringUtils.EMPTY; + if (CastleRight.KING_AND_QUEEN_SIDE.equals(castleRight.get(Side.WHITE))) + { + rights += "KQ"; + } + else if (CastleRight.KING_SIDE.equals(castleRight.get(Side.WHITE))) + { + rights += "K"; + } + else if (CastleRight.QUEEN_SIDE.equals(castleRight.get(Side.WHITE))) + { + rights += "Q"; + } + + if (CastleRight.KING_AND_QUEEN_SIDE.equals(castleRight.get(Side.BLACK))) + { + rights += "kq"; + } + else if (CastleRight.KING_SIDE.equals(castleRight.get(Side.BLACK))) + { + rights += "k"; + } + else if (CastleRight.QUEEN_SIDE.equals(castleRight.get(Side.BLACK))) + { + rights += "q"; + } + + if (StringUtils.isEmpty(rights)) + { + fen.append(" -"); + } + else + { + fen.append(StringUtils.SPACE + rights); + } + + if (Square.NONE.equals(getEnPassant()) || (onlyOutputEnPassantIfCapturable && !pawnCanBeCapturedEnPassant())) + { + fen.append(" -"); + } + else + { + fen.append(StringUtils.SPACE); + fen.append(getEnPassant().toString().toLowerCase()); + } + + if (includeCounters) + { + fen.append(StringUtils.SPACE); + fen.append(getHalfMoveCounter()); + fen.append(StringUtils.SPACE); + fen.append(getMoveCounter()); + } + + return fen.toString(); + } + + /** + * Returns an array of pieces that represents the current position on the board. + * For each index, the array holds the piece present on the square with the same + * index, or {@link Piece#NONE} if the square is empty. + * + * @return the array that contains the pieces on the board + */ + public Piece[] boardToArray() + { + final Piece[] pieces = new Piece[65]; + pieces[64] = Piece.NONE; + + for (Square square : Square.values()) + { + if (!Square.NONE.equals(square)) + { + pieces[square.ordinal()] = getPiece(square); + } + } + + return pieces; + } + + /** + * Returns the bitboard representing the pieces of a specific side that can + * attack the given square. + *

+ * Same as invoking {@code squareAttackedBy(square, side, getBitboard())}. + * + * @param square the target square + * @param side the attacking side + * @return the bitboard of all the pieces of the given side that can attack the + * square + * @see Board#squareAttackedBy(Square, Side, long) + */ + public long squareAttackedBy(Square square, Side side) + { + return squareAttackedBy(square, side, getBitboard()); + } + + /** + * Returns the bitboard representing the pieces of a specific side that can + * attack the given square. It takes a bitboard mask in input to filter the + * result for a specific set of occupied squares only. + * + * @param square the target square + * @param side the attacking side + * @param occ a mask of occupied squares + * @return the bitboard of all the pieces of the given side that can attack the + * square + */ + public long squareAttackedBy(Square square, Side side, long occ) + { + long result; + result = Attacks.getPawnAttacks(side.flip(), square.getBitboard()) + & getBitboard(Piece.make(side, PieceType.PAWN)) & occ; + result |= Attacks.getKnightAttacks(square, occ) & getBitboard(Piece.make(side, PieceType.KNIGHT)); + result |= Attacks.getBishopAttacks(occ, square) + & ((getBitboard(Piece.make(side, PieceType.BISHOP)) | getBitboard(Piece.make(side, PieceType.QUEEN)))); + result |= Attacks.getRookAttacks(occ, square) + & ((getBitboard(Piece.make(side, PieceType.ROOK)) | getBitboard(Piece.make(side, PieceType.QUEEN)))); + result |= Attacks.getKingAttacks(square, occ) & getBitboard(Piece.make(side, PieceType.KING)); + return result; + } + + /** + * Returns the bitboard representing the pieces of a specific side and type that + * can attack the given square. + *

+ * Same as invoking + * {@code squareAttackedByPieceType(square, side, type, getBitboard())}. + * + * @param square the target square + * @param side the attacking side + * @param type the type of the attacking pieces + * @return the bitboard of all the pieces of the given side and type that can + * attack the square + */ + public long squareAttackedByPieceType(Square square, Side side, PieceType type) + { + return squareAttackedByPieceType(square, side, type, getBitboard()); + } + + /** + * Returns the bitboard representing the pieces of a specific side and type that + * can attack the given square. + * + * @param square the target square + * @param side the attacking side + * @param type the type of the attacking pieces + * @param occ a mask of occupied squares + * @return the bitboard of all the pieces of the given side and type that can + * attack the square + */ + public long squareAttackedByPieceType(Square square, Side side, PieceType type, long occ) + { + long result = 0L; + switch (type) + { + case PAWN: + result = Attacks.getPawnAttacks(side.flip(), square.getBitboard()) + & getBitboard(Piece.make(side, PieceType.PAWN)); + break; + case KNIGHT: + result = Attacks.getKnightAttacks(square, occ) & getBitboard(Piece.make(side, PieceType.KNIGHT)); + break; + case BISHOP: + result = Attacks.getBishopAttacks(occ, square) & getBitboard(Piece.make(side, PieceType.BISHOP)); + break; + case ROOK: + result = Attacks.getRookAttacks(occ, square) & getBitboard(Piece.make(side, PieceType.ROOK)); + break; + case QUEEN: + result = Attacks.getQueenAttacks(occ, square) & getBitboard(Piece.make(side, PieceType.QUEEN)); + break; + case KING: + result |= Attacks.getKingAttacks(square, occ) & getBitboard(Piece.make(side, PieceType.KING)); + break; + default: + break; + } + return result; + } + + /** + * Returns the square occupied by the king of the given side. + * + * @param side the side of the king + * @return the square occupied by the king + */ + public Square getKingSquare(Side side) + { + Square result = Square.NONE; + long piece = getBitboard(Piece.make(side, PieceType.KING)); + if (piece != 0L) + { + int sq = Bitboard.bitScanForward(piece); + return Square.squareAt(sq); + } + return result; + } + + /** + * Checks if the king of the side to move is attacked by any enemy piece. + * + * @return {@code true} if the king of the next side to move is attacked + */ + public boolean isKingAttacked() + { + return squareAttackedBy(getKingSquare(getSideToMove()), getSideToMove().flip()) != 0; + } + + /** + * Checks whether a piece from a given square attacks any member of a set of + * squares + * + * @param from the square the piece attacks from + * @param to the bitboard of squares to be checked + * @param pt the type of the attacking piece + * @param occ a mask of occupied squares + * @return {@code true} if the move attacks any member of the given square set + */ + private boolean isAttackedByPiece(Square from, long to, PieceType pt, long occ) + { + switch (pt) + { + case PAWN: + return 0L != (to & Attacks.getPawnAttacks(getSideToMove(), from.getBitboard())); + case KNIGHT: + return 0L != (to & Attacks.getKnightAttacks(from, occ)); + case BISHOP: + return 0L != (to & Attacks.getBishopAttacks(occ, from)); + case ROOK: + return 0L != (to & Attacks.getRookAttacks(occ, from)); + case QUEEN: + return 0L != (to & Attacks.getQueenAttacks(occ, from)); + default: + return false; + } + } + + /** + * Checks if the move attacks the king of the other side. + * + * @return {@code true} if the move attacks the king of the other side + */ + public boolean attacksKing(Move move) + { + PieceType moved = getPiece(move.getFrom()).getPieceType(); + + long occ = getBitboard(); + long king = getBitboard(Piece.make(getSideToMove().flip(), PieceType.KING)); + + if (isAttackedByPiece(move.getTo(), king, moved, getBitboard())) + { + return true; + } + + Square kingSquare = Square.squareAt(Bitboard.bitScanForward(king)); + + long newOcc = (occ ^ move.getFrom().getBitboard()) | move.getTo().getBitboard(); + long newBishopAttacks = Attacks.getBishopAttacks(newOcc, kingSquare); + long newRookAttacks = Attacks.getRookAttacks(newOcc, kingSquare); + + long bishops = getBitboard(Piece.make(getSideToMove(), PieceType.BISHOP)); + long rooks = getBitboard(Piece.make(getSideToMove(), PieceType.ROOK)); + long queens = getBitboard(Piece.make(getSideToMove(), PieceType.QUEEN)); + + if (0L != ((bishops | queens) & newBishopAttacks)) + { + return true; + } + + if (0L != ((rooks | queens) & newRookAttacks)) + { + return true; + } + + if (!move.getPromotion().equals(Piece.NONE)) + { + return isAttackedByPiece(move.getTo(), king, move.getPromotion().getPieceType(), newOcc); + } + + if (PieceType.KING.equals(moved)) + { + if (move.equals(context.getWhiteoo())) + { + return 0L != (newRookAttacks & context.getWhiteRookoo().getTo().getBitboard()); + } + + if (move.equals(context.getWhiteooo())) + { + return 0L != (newRookAttacks & context.getWhiteRookooo().getTo().getBitboard()); + } + + if (move.equals(context.getBlackoo())) + { + return 0L != (newRookAttacks & context.getBlackRookoo().getTo().getBitboard()); + } + + if (move.equals(context.getBlackooo())) + { + return 0L != (newRookAttacks & context.getBlackRookooo().getTo().getBitboard()); + } + } + + return false; + } + + /** + * Checks if any of the squares provided in input is attacked by the given side + * in the current position. + * + * @param squares the target squares + * @param side the attacking side + * @return {@code true} if any square is attacked + */ + public boolean isSquareAttackedBy(List squares, Side side) + { + for (Square sq : squares) + { + if (squareAttackedBy(sq, side) != 0L) + { + return true; + } + } + + return false; + } + + /** + * Verifies if the move still to be executed can be performed. This checks if it + * is possible to move the piece at from square to the piece at to square. This + * does not check if a move leaves the king in check + * + * @param move the move to validate + * @return {@code true} if the move is considered pseudo-legal + */ + public boolean isMovePseudoLegal(Move move) + { + if (Piece.NONE.equals(getPiece(move.getFrom())) || !isMoveLegal(move, true)) + { + return false; + } + + Square from = move.getFrom(); + Square to = move.getTo(); + Piece movedPiece = getPiece(move.getFrom()); + Side side = movedPiece.getPieceSide(); + PieceType movedPieceType = movedPiece.getPieceType(); + + long occupied = getBitboard(); + + if (movedPiece.getPieceType().equals(PieceType.KING) && getContext().isCastleMove(move)) + { + return !isKingAttacked(); + } + + if (0L != (getBitboard(side) & to.getBitboard())) + { + return false; + } + + switch (movedPieceType) + { + case PAWN: + long pawnThreats = Attacks.getPawnCaptures(side, from.getBitboard(), + to.getBitboard() & (getBitboard(side.flip()) | getEnPassant().getBitboard()), getEnPassant()) + & to.getBitboard(); + pawnThreats |= Attacks.getPawnMoves(side, from.getBitboard(), occupied) & to.getBitboard(); + return 0L != pawnThreats; + case KNIGHT: + return 0L != Attacks.getKnightAttacks(from, to.getBitboard()); + case BISHOP: + return 0L != (Attacks.getBishopAttacks(occupied, from) & to.getBitboard()); + case ROOK: + return 0L != (Attacks.getRookAttacks(occupied, from) & to.getBitboard()); + case QUEEN: + return 0L != (Attacks.getQueenAttacks(occupied, from) & to.getBitboard()); + case KING: + return 0L != Attacks.getKingAttacks(from, to.getBitboard()); + default: + return false; + } + } + + /** + * Verifies if the move still to be executed will leave the resulting board in a + * valid (legal) position. Optionally, it can perform a full validation, a + * stricter check to assess if the final board configuration could be considered + * valid or not. + *

+ * The full validation checks: + *

    + *
  • if a piece is actually moving;
  • + *
  • if the moving side is the next side to move in the position;
  • + *
  • if the destination square does not contain a piece of the same side of + * the moving one;
  • + *
  • in case of a promotion, if a promoting piece is present;
  • + *
  • in case of castling, if the castle move can be performed.
  • + *
+ * N.B.: the method does not check whether the move is legal or not + * according to the standard chess rules, but only if the resulting + * configuration is valid. For instance, it is considered valid moving the king + * by two or more squares, or a rook beyond its friendly pieces, as long as the + * position obtained after the move does not violate any chess constraint. + * + * @param move the move to validate + * @param fullValidation performs a full validation of the move + * @return {@code true} if the move is considered valid + */ + public boolean isMoveLegal(Move move, boolean fullValidation) + { + final Piece fromPiece = getPiece(move.getFrom()); + final Side side = getSideToMove(); + final PieceType fromType = fromPiece.getPieceType(); + final Piece capturedPiece = getPiece(move.getTo()); + + if (fullValidation) + { + if (Piece.NONE.equals(fromPiece)) + { + throw new RuntimeException("From piece cannot be null"); + } + + if (fromPiece.getPieceSide().equals(capturedPiece.getPieceSide())) + { + return false; + } + + if (!side.equals(fromPiece.getPieceSide())) + { + return false; + } + + boolean pawnPromoting = fromPiece.getPieceType().equals(PieceType.PAWN) && isPromoRank(side, move); + boolean hasPromoPiece = !move.getPromotion().equals(Piece.NONE); + + if (hasPromoPiece != pawnPromoting) + { + return false; + } + + if (fromType.equals(PieceType.KING)) + { + if (getContext().isKingSideCastle(move)) + { + if (getCastleRight(side).equals(CastleRight.KING_AND_QUEEN_SIDE) + || (getCastleRight(side).equals(CastleRight.KING_SIDE))) + { + if ((getBitboard() & getContext().getooAllSquaresBb(side)) == 0L) + { + return !isSquareAttackedBy(getContext().getooSquares(side), side.flip()); + } + } + return false; + } + + if (getContext().isQueenSideCastle(move)) + { + if (getCastleRight(side).equals(CastleRight.KING_AND_QUEEN_SIDE) + || (getCastleRight(side).equals(CastleRight.QUEEN_SIDE))) + { + if ((getBitboard() & getContext().getoooAllSquaresBb(side)) == 0L) + { + return !isSquareAttackedBy(getContext().getoooSquares(side), side.flip()); + } + } + + return false; + } + } + } + + if (fromType.equals(PieceType.KING)) + { + if (squareAttackedBy(move.getTo(), side.flip()) != 0L) + { + return false; + } + } + + Square kingSq = (fromType.equals(PieceType.KING) ? move.getTo() : getKingSquare(side)); + Side other = side.flip(); + long moveTo = move.getTo().getBitboard(); + long moveFrom = move.getFrom().getBitboard(); + long ep = getEnPassantTarget() != Square.NONE && move.getTo() == getEnPassant() + && (fromType.equals(PieceType.PAWN)) ? getEnPassantTarget().getBitboard() : 0; + long allPieces = (getBitboard() ^ moveFrom ^ ep) | moveTo; + + long bishopAndQueens = ((getBitboard(Piece.make(other, PieceType.BISHOP)) + | getBitboard(Piece.make(other, PieceType.QUEEN)))) & ~moveTo; + + if (bishopAndQueens != 0L && (Attacks.getBishopAttacks(allPieces, kingSq) & bishopAndQueens) != 0L) + { + return false; + } + + long rookAndQueens = ((getBitboard(Piece.make(other, PieceType.ROOK)) + | getBitboard(Piece.make(other, PieceType.QUEEN)))) & ~moveTo; + + if (rookAndQueens != 0L && (Attacks.getRookAttacks(allPieces, kingSq) & rookAndQueens) != 0L) + { + return false; + } + + long knights = (getBitboard(Piece.make(other, PieceType.KNIGHT))) & ~moveTo; + + if (knights != 0L && (Attacks.getKnightAttacks(kingSq, allPieces) & knights) != 0L) + { + return false; + } + + long pawns = (getBitboard(Piece.make(other, PieceType.PAWN))) & ~moveTo & ~ep; + + return pawns == 0L || (Attacks.getPawnAttacks(side, kingSq.getBitboard()) & pawns) == 0L; + } + + /** + * Checks if the squares of a move are consistent, that is, if the destination + * square is attacked by the piece placed on the starting square. + * + * @param move the move to check + * @return {@code true} if the move is coherent + */ + public boolean isAttackedBy(Move move) + { + PieceType pieceType = getPiece(move.getFrom()).getPieceType(); + assert (!PieceType.NONE.equals(pieceType)); + Side side = getSideToMove(); + long attacks = 0L; + switch (pieceType) + { + case PAWN: + if (!move.getFrom().getFile().equals(move.getTo().getFile())) + { + attacks = Attacks.getPawnCaptures(side, move.getFrom().getBitboard(), getBitboard(), + getEnPassantTarget()); + } + else + { + attacks = Attacks.getPawnMoves(side, move.getFrom().getBitboard(), getBitboard()); + } + break; + case KNIGHT: + attacks = Attacks.getKnightAttacks(move.getFrom(), ~getBitboard(side)); + break; + case BISHOP: + attacks = Attacks.getBishopAttacks(getBitboard(), move.getFrom()); + break; + case ROOK: + attacks = Attacks.getRookAttacks(getBitboard(), move.getFrom()); + break; + case QUEEN: + attacks = Attacks.getQueenAttacks(getBitboard(), move.getFrom()); + break; + case KING: + attacks = Attacks.getKingAttacks(move.getFrom(), ~getBitboard(side)); + break; + default: + break; + } + return (attacks & move.getTo().getBitboard()) != 0L; + } + + /** + * Returns the history of the board, represented by the hashes of all the + * positions occurred on the board. + * + * @return the list of hashes of all the positions occurred on the board + * @see Board#getIncrementalHashKey() + */ + public LinkedList getHistory() + { + return history; + } + + /** + * Verifies in the current position if the king of the side to move is mated. + * + * @return {@code true} if the king of the side to move is checkmated + */ + public boolean isMated() + { + try + { + if (isKingAttacked()) + { + List l = new LinkedList(); + MoveGenerator.generateLegalMoves(this, l); + + if (l.size() == 0) + { + return true; + } + } + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + return false; + } + + /** + * Verifies if the current position is a forced draw because any of the standard + * chess rules. Specifically, the method checks for: + *
    + *
  • threefold repetition;
  • + *
  • insufficient material;
  • + *
  • fifty-move rule;
  • + *
  • stalemate.
  • + *
+ * + * @return {@code true} if the position is a draw + */ + public boolean isDraw() + { + if (isRepetition()) + { + return true; + } + + if (isInsufficientMaterial()) + { + return true; + } + + if (getHalfMoveCounter() >= 100) + { + return true; + } + + return isStaleMate(); + } + + /** + * Verifies if the current position has been repeated at least n times, + * where n is provided in input. + * + * @param n the number of repetitions to check in the position + * @return {@code true} if the position has been repeated at least n + * times + */ + public boolean isRepetition(int n) + { + + final int i = Math.min(getHistory().size() - 1, getHalfMoveCounter()); + if (getHistory().size() >= 4) + { + long lastKey = getHistory().get(getHistory().size() - 1); + int rep = 0; + for (int x = 4; x <= i; x += 2) + { + final long k = getHistory().get(getHistory().size() - x - 1); + if (k == lastKey && ++rep >= n - 1) + { + return true; + } + } + } + return false; + } + + /** + * Verifies if the current position has been repeated at least three times + * (threefold repetition). + *

+ * Same as invoking {@code isRepetition(3)}. + * + * @return {@code true} if the position has been repeated at least three times + * @see Board#isRepetition(int) + */ + public boolean isRepetition() + { + + return isRepetition(3); + } + + /** + * Verifies if the current position has insufficient material to continue the + * game, and thus it must be considered a forced draw. + * + * @return {@code true} if the position has insufficient material + */ + public boolean isInsufficientMaterial() + { + if ((getBitboard(Piece.WHITE_QUEEN) + getBitboard(Piece.BLACK_QUEEN) + getBitboard(Piece.WHITE_ROOK) + + getBitboard(Piece.BLACK_ROOK)) != 0L) + { + return false; + } + + final long pawns = getBitboard(Piece.WHITE_PAWN) | getBitboard(Piece.BLACK_PAWN); + if (pawns == 0L) + { + long count = Long.bitCount(getBitboard()); + int whiteCount = Long.bitCount(getBitboard(Side.WHITE)); + int blackCount = Long.bitCount(getBitboard(Side.BLACK)); + + if (count == 4) + { + int whiteBishopCount = Long.bitCount(getBitboard(Piece.WHITE_BISHOP)); + int blackBishopCount = Long.bitCount(getBitboard(Piece.BLACK_BISHOP)); + + if (whiteCount > 1 && blackCount > 1) + { + return !((whiteBishopCount == 1 && blackBishopCount == 1) + && getFistPieceLocation(Piece.WHITE_BISHOP) + .isLightSquare() != getFistPieceLocation(Piece.BLACK_BISHOP).isLightSquare()); + } + + if (whiteCount == 3 || blackCount == 3) + { + if (whiteBishopCount == 2 && ((Bitboard.lightSquares & getBitboard(Piece.WHITE_BISHOP)) == 0L + || (Bitboard.darkSquares & getBitboard(Piece.WHITE_BISHOP)) == 0L)) + { + return true; + } + + else + return blackBishopCount == 2 && ((Bitboard.lightSquares & getBitboard(Piece.BLACK_BISHOP)) == 0L + || (Bitboard.darkSquares & getBitboard(Piece.BLACK_BISHOP)) == 0L); + } + + else + { + return Long.bitCount(getBitboard(Piece.WHITE_KNIGHT)) == 2 + || Long.bitCount(getBitboard(Piece.BLACK_KNIGHT)) == 2; + } + } + + else + { + if ((getBitboard(Piece.WHITE_KING) | getBitboard(Piece.WHITE_BISHOP)) == getBitboard(Side.WHITE) + && ((getBitboard(Piece.BLACK_KING) | getBitboard(Piece.BLACK_BISHOP)) == getBitboard( + Side.BLACK))) + { + return (((Bitboard.lightSquares & getBitboard(Piece.WHITE_BISHOP)) == 0L) + && ((Bitboard.lightSquares & getBitboard(Piece.BLACK_BISHOP)) == 0L)) + || ((Bitboard.darkSquares & getBitboard(Piece.WHITE_BISHOP)) == 0L) + && ((Bitboard.darkSquares & getBitboard(Piece.BLACK_BISHOP)) == 0L); + } + return count < 4; + } + } + + return false; + } + + /** + * Verifies in the current position if the king of the side to move is + * stalemated, and thus if the position must be considered a forced draw. + * + * @return {@code true} if the king of the side to move is stalemated + */ + public boolean isStaleMate() + { + try + { + if (!isKingAttacked()) + { + List l = new LinkedList(); + MoveGenerator.generateLegalMoves(this, l); + + if (l.size() == 0) + { + return true; + } + } + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + return false; + } + + /** + * Returns whether the notifications of board events are enabled or not. + * + * @return {@code true} if board events are notified to observers + */ + public boolean isEnableEvents() + { + return enableEvents; + } + + /** + * Sets the flag that controls the notification of board events. If + * {@code true}, board events are emitted, otherwise they are turned off. + * + * @param enableEvents whether the notification of board events is enabled or + * not + */ + public void setEnableEvents(boolean enableEvents) + { + this.enableEvents = enableEvents; + } + + /** + * Returns the unique position ID for the current position and status. The + * identifier is nothing more than the Forsyth-Edwards Notation (FEN) + * representation of the board without the move counters. + *

+ * Although this is a reliable way for identifying a unique position, it is much + * slower than using {@link Board#hashCode()} or {@link Board#getZobristKey()}. + * + * @return the unique position ID + * @see Board#hashCode() + * @see Board#getZobristKey() + */ + public String getPositionId() + { + String[] parts = this.getFen(false).split(StringUtils.SPACE); + return parts[0] + StringUtils.SPACE + parts[1] + StringUtils.SPACE + parts[2] + + (this.getEnPassantTarget() != Square.NONE ? parts[3] : "-"); + } + + /** + * Returns the list of all possible legal moves for the current position + * according to the standard rules of chess. If such moves are played, it is + * guaranteed the resulting position will also be legal. + * + * @param moves the list to write generated moves to + */ + public void generateLegalMoves(List moves) + { + MoveGenerator.generateLegalMoves(this, moves); + } + + /** + * Returns the list of all possible pseudo-legal moves for the current position. + *

+ * A move is considered pseudo-legal when it is legal according to the standard + * rules of chess piece movements, but the resulting position might not be legal + * because of other rules (e.g. checks to the king). + * + * @param moves the list to write generated moves to + */ + public void generatePseudoLegalMoves(List moves) + { + MoveGenerator.generatePseudoLegalMoves(this, moves); + } + + /** + * Returns the list of all possible pseudo-legal captures for the current + * position. + *

+ * A move is considered a pseudo-legal capture when it takes an enemy piece and + * it is legal according to the standard rules of chess piece movements, but the + * resulting position might not be legal because of other rules (e.g. checks to + * the king). + * + * @param moves the list to write generated moves to + */ + public void generatePseudoLegalCaptures(List moves) + { + MoveGenerator.generatePseudoLegalCaptures(this, moves); + } + + /** + * Returns the list of all possible legal moves for the current position + * according to the standard rules of chess. If such moves are played, it is + * guaranteed the resulting position will also be legal. + * + * @return the list of legal moves available in the current position + */ + public List legalMoves() + { + List moves = new LinkedList(); + generateLegalMoves(moves); + return moves; + } + + /** + * Returns the list of all possible pseudo-legal moves for the current position. + *

+ * A move is considered pseudo-legal when it is legal according to the standard + * rules of chess piece movements, but the resulting position might not be legal + * because of other rules (e.g. checks to the king). + * + * @return the list of pseudo-legal moves available in the current position + */ + public List pseudoLegalMoves() + { + List moves = new LinkedList(); + generatePseudoLegalMoves(moves); + return moves; + } + + /** + * Returns the list of all possible pseudo-legal captures for the current + * position. + *

+ * A move is considered a pseudo-legal capture when it takes an enemy piece and + * it is legal according to the standard rules of chess piece movements, but the + * resulting position might not be legal because of other rules (e.g. checks to + * the king). + * + * @return the list of pseudo-legal captures available in the current position + */ + public List pseudoLegalCaptures() + { + List moves = new LinkedList(); + generatePseudoLegalCaptures(moves); + return moves; + } + + /** + * Checks if this board is equivalent to another. + *

+ * Two boards are considered equivalent when: + *

    + *
  • the pieces are the same, placed on the very same squares;
  • + *
  • the side to move is the same;
  • + *
  • the castling rights are the same;
  • + *
  • the en passant target is the same.
  • + *
+ * + * @param obj the other object reference to compare to this board + * @return {@code true} if this board and the object reference are equivalent + * @see Board#strictEquals(Object) + */ + @Override + public boolean equals(Object obj) + { + if (obj instanceof Board) + { + Board board = (Board) obj; + for (Piece piece : Piece.allPieces) + { + if (piece != Piece.NONE && getBitboard(piece) != board.getBitboard(piece)) + { + return false; + } + } + return getSideToMove() == board.getSideToMove() + && getCastleRight(Side.WHITE) == board.getCastleRight(Side.WHITE) + && getCastleRight(Side.BLACK) == board.getCastleRight(Side.BLACK) + && getEnPassant() == board.getEnPassant() && getEnPassantTarget() == board.getEnPassantTarget(); + + } + return false; + } + + /** + * Checks if this board is equivalent to another performing a strict comparison. + *

+ * Two boards are considered strictly equivalent when: + *

    + *
  • they are equivalent;
  • + *
  • their history is the same.
  • + *
+ * + * @param obj the other object reference to compare to this board + * @return {@code true} if this board and the object reference are strictly + * equivalent + * @see Board#equals(Object) + */ + public boolean strictEquals(Object obj) + { + if (obj instanceof Board) + { + Board board = (Board) obj; + return equals(board) && board.getHistory().equals(this.getHistory()); + } + return false; + } + + /** + * Returns a hash code value for this board. + * + * @return a hash value for this board + */ + @Override + public int hashCode() + { + return (int) incrementalHashKey; + } + + /** + * Returns a Zobrist hash code value for this board. A Zobrist hashing assures + * the same position returns the same hash value. It is calculated using the + * position of the pieces, the side to move, the castle rights and the en + * passant target. + * + * @return a Zobrist hash value for this board + * @see Zobrist hashing + * in Wikipedia + */ + public long getZobristKey() + { + long hash = 0; + if (getCastleRight(Side.WHITE) != CastleRight.NONE) + { + hash ^= getCastleRightKey(Side.WHITE); + } + if (getCastleRight(Side.BLACK) != CastleRight.NONE) + { + hash ^= getCastleRightKey(Side.BLACK); + } + for (Square sq : Square.values()) + { + Piece piece = getPiece(sq); + if (!Piece.NONE.equals(piece) && !Square.NONE.equals(sq)) + { + hash ^= getPieceSquareKey(piece, sq); + } + } + hash ^= getSideKey(getSideToMove()); + + if (Square.NONE != getEnPassantTarget() && pawnCanBeCapturedEnPassant()) + { + hash ^= getEnPassantKey(getEnPassantTarget()); + } + return hash; + } + + private long getCastleRightKey(Side side) + { + return keys.get(3 * getCastleRight(side).ordinal() + 300 + 3 * side.ordinal()); + } + + private long getSideKey(Side side) + { + return keys.get(3 * side.ordinal() + 500); + } + + private long getEnPassantKey(Square enPassantTarget) + { + return keys.get(3 * enPassantTarget.ordinal() + 400); + } + + private long getPieceSquareKey(Piece piece, Square square) + { + return keys.get(57 * piece.ordinal() + 13 * square.ordinal()); + } + + /** + * Returns a human-readable representation of the board taking the perspective + * of white, with the 1st rank at the bottom and the 8th rank at the top. + *

+ * Same as invoking {@code toStringFromViewPoint(Side.WHITE)}. + * + * @return a string representation of the board from white player's point of + * view + * @see Board#toStringFromViewPoint(Side) + */ + public String toStringFromWhiteViewPoint() + { + return toStringFromViewPoint(Side.WHITE); + } + + /** + * Returns a human-readable representation of the board taking the perspective + * of black, with the 8th rank at the bottom and the 1st rank at the top. + *

+ * Same as invoking {@code toStringFromViewPoint(Side.BLACK)}. + * + * @return a string representation of the board from black player's point of + * view + * @see Board#toStringFromViewPoint(Side) + */ + public String toStringFromBlackViewPoint() + { + return toStringFromViewPoint(Side.BLACK); + } + + /** + * Returns a human-readable representation of the board taking the perspective + * of one side, with the 1st rank at the bottom in case of white, or the 8th + * rank at the bottom in case of black. + * + * @param side the side whose home rank should be at the bottom of the resulting + * representation + * @return a string representation of the board using one of the two player's + * point of view + */ + public String toStringFromViewPoint(Side side) + { + StringBuilder sb = new StringBuilder(); + + final Supplier rankIterator = side == Side.WHITE ? Board::sevenToZero : Board::zeroToSeven; + final Supplier fileIterator = side == Side.WHITE ? Board::zeroToSeven : Board::sevenToZero; + + rankIterator.get().forEach(i -> { + Rank r = Rank.allRanks[i]; + fileIterator.get().forEach(n -> { + File f = File.allFiles[n]; + if (!File.NONE.equals(f) && !Rank.NONE.equals(r)) + { + Square sq = Square.encode(r, f); + Piece piece = getPiece(sq); + sb.append(piece.getFenSymbol()); + } + }); + sb.append("\n"); + }); + + return sb.toString(); + } + + /** + * Returns a string representation of this board. + *

+ * The result of {@link Board#toStringFromWhiteViewPoint()} is used to print the + * position of the board. + * + * @return a string representation of the board + * @see Board#toStringFromWhiteViewPoint() + */ + @Override + public String toString() + { + return toStringFromWhiteViewPoint() + "Side: " + getSideToMove(); + } + + /** + * Returns a reference to a copy of the board. The board history is copied as + * well. + * + * @return a copy of the board + */ + @Override + public Board clone() + { + Board copy = new Board(getContext(), this.updateHistory); + copy.loadFromFen(this.getFen()); + copy.setEnPassantTarget(this.getEnPassantTarget()); + copy.getHistory().clear(); + + for (long key : getHistory()) + { + copy.getHistory().add(key); + } + + return copy; + } + + /** + * Returns the current incremental hash key. This hash value changes every time + * the position changes, hence it is unique for every position. + * + * @return the current incremental hash key + */ + public long getIncrementalHashKey() + { + return incrementalHashKey; + } + + /** + * Sets the current incremental hash key, replacing the previous one. + * + * @param hashKey the incremental hash key to set + */ + public void setIncrementalHashKey(long hashKey) + { + incrementalHashKey = hashKey; + } + + /** + * Returns whether the given side has material other than pawns + * + * @param side the side to check + * @return {@code true} if the side has non-pawn material + */ + public boolean hasNonPawnMaterial(Side side) + { + return (getBitboard(Piece.make(side, PieceType.KING)) + | getBitboard(Piece.make(side, PieceType.PAWN))) != getBitboard(side); + } + + /** + * Returns whether the side to move has material other than pawns + *

+ * Same as invoking {@code hasNonPawnMaterial(getSideToMove())}. + * + * @return {@code true} if the side to move has non-pawn material + */ + public boolean hasNonPawnMaterial() + { + return hasNonPawnMaterial(getSideToMove()); + } + + private static final int[] SEEPieceValues = new int[] { 103, 422, 437, 694, 1313, 0 }; + + /** + * Returns the estimated value of a given move, assuming no recaptures. + * + * @param move the move to make + * @return the estimate value of the move + */ + public int moveEstimatedValue(Move move) + { + // Start with the value of the piece on the target square + int value = !getPiece(move.getTo()).equals(Piece.NONE) + ? SEEPieceValues[getPiece(move.getTo()).getPieceType().ordinal()] + : 0; + + // Factor in the new piece's value and remove our promoted pawn + if (!Piece.NONE.equals(move.getPromotion())) + value += SEEPieceValues[move.getPromotion().getPieceType().ordinal()] + - SEEPieceValues[PieceType.PAWN.ordinal()]; + + // Target square is encoded as empty for enpass moves + else if (PieceType.PAWN.equals(getPiece(move.getFrom()).getPieceType()) && getEnPassant().equals(move.getTo())) + value = SEEPieceValues[PieceType.PAWN.ordinal()]; + + return value; + } + + /** + * Returns whether the static exchange evaluation (SEE) of a move beats a given + * threshold. The static exchange evaluation is the estimated material gain + * after a series of exchanges. + * + * @param move the move to make + * @param threshold the SEE threshold + * @return {@code true} if the exchange beats the given threshold + */ + public boolean staticExchangeEvaluation(Move move, int threshold) + { + Square from, to; + PieceType nextVictim; + Side color; + int balance; + long bishops, rooks, occupied, attackers, myAttackers; + boolean isPromotion, isEnPassant; + + // Unpack move information + from = move.getFrom(); + to = move.getTo(); + + isPromotion = !Piece.NONE.equals(move.getPromotion()); + isEnPassant = PieceType.PAWN.equals(getPiece(from).getPieceType()) && getEnPassant().equals(to); + + // Next victim is moved piece or promotion type + nextVictim = !isPromotion ? getPiece(from).getPieceType() : move.getPromotion().getPieceType(); + + // Balance is the value of the move minus threshold. Function + // call takes care for Enpass, Promotion and Castling moves. + balance = moveEstimatedValue(move) - threshold; + + // Best case still fails to beat the threshold + if (balance < 0) + return false; + + // Worst case is losing the moved piece + balance -= SEEPieceValues[nextVictim.ordinal()]; + + // If the balance is positive even if losing the moved piece, + // the exchange is guaranteed to beat the threshold. + if (balance >= 0) + return true; + + // Grab sliders for updating revealed attackers + bishops = getBitboard(PieceType.BISHOP) | getBitboard(PieceType.QUEEN); + rooks = getBitboard(PieceType.ROOK) | getBitboard(PieceType.QUEEN); + + // Let occupied suppose that the move was actually made + occupied = getBitboard(); + occupied = (occupied ^ from.getBitboard()) | to.getBitboard(); + if (isEnPassant) + occupied ^= getEnPassant().getBitboard(); + + // Get all pieces which attack the target square. And with occupied + // so that we do not let the same piece attack twice + attackers = squareAttackedBy(to, getSideToMove(), occupied) + | squareAttackedBy(to, getSideToMove().flip(), occupied) & occupied; + + // Now our opponents turn to recapture + color = getSideToMove().flip(); + + while (true) + { + // If we have no more attackers left we lose + myAttackers = attackers & getBitboard(color); + + if (myAttackers == 0) + break; + + if (0L != (myAttackers & getBitboard(Piece.make(color, PieceType.PAWN)))) + { + nextVictim = PieceType.PAWN; + } + + else if (0L != (myAttackers & getBitboard(Piece.make(color, PieceType.KNIGHT)))) + { + nextVictim = PieceType.KNIGHT; + } + + else if (0L != (myAttackers & getBitboard(Piece.make(color, PieceType.BISHOP)))) + { + nextVictim = PieceType.BISHOP; + } + + else if (0L != (myAttackers & getBitboard(Piece.make(color, PieceType.ROOK)))) + { + nextVictim = PieceType.ROOK; + } + + else if (0L != (myAttackers & getBitboard(Piece.make(color, PieceType.QUEEN)))) + { + nextVictim = PieceType.QUEEN; + } + + else if (0L != (myAttackers & getBitboard(Piece.make(color, PieceType.KING)))) + { + nextVictim = PieceType.KING; + } + + else + { + assert (false); + } + + // Remove this attacker from the occupied + occupied ^= (1L << Bitboard.bitScanForward(myAttackers & getBitboard(Piece.make(color, nextVictim)))); + + // A diagonal move may reveal bishop or queen attackers + if (nextVictim.equals(PieceType.PAWN) || nextVictim.equals(PieceType.BISHOP) + || nextVictim.equals(PieceType.QUEEN)) + attackers |= Attacks.getBishopAttacks(occupied, to) & bishops; + + // A vertical or horizontal move may reveal rook or queen attackers + if (nextVictim.equals(PieceType.ROOK) || nextVictim.equals(PieceType.QUEEN)) + attackers |= Attacks.getRookAttacks(occupied, to) & rooks; + + // Make sure we did not add any already used attacks + attackers &= occupied; + + // Swap the turn + color = color.flip(); + + // Negamax the balance and add the value of the next victim + balance = -balance - 1 - SEEPieceValues[nextVictim.ordinal()]; + + // If the balance is non-negative after giving away our piece then we win + if (balance >= 0) + { + // As a slide speed up for move legality checking, if our last attacking + // piece is a king, and our opponent still has attackers, then we've + // lost as the move we followed would be illegal + if (nextVictim.equals(PieceType.KING) && (attackers & getBitboard(color)) != 0) + color = color.flip(); + + break; + } + } + + // Side to move after the loop loses + return !getSideToMove().equals(color); + } + + /** + * Returns whether a move is quiet. A move is quiet if it is neither a promotion + * or a capture. + * + * @param move the move + * @return {@code true} if the move is quiet + */ + public boolean isQuiet(Move move) + { + return !isPromotion(move) && !isCapture(move); + } + + /** + * Returns whether a move is a capture. + * + * @param move the move + * @return {@code true} if the move is a capture + */ + public boolean isCapture(Move move) + { + return !Piece.NONE.equals(getPiece(move.getTo())) + || (PieceType.PAWN.equals(getPiece(move.getFrom()).getPieceType()) && move.getTo() == getEnPassant()); + } + + /** + * Returns whether a move is a promotion. + * + * @param move the move + * @return {@code true} if the move is a promotion + */ + public boolean isPromotion(Move move) + { + return move.isPromotion(); + } + + private boolean pawnCanBeCapturedEnPassant() + { + return squareAttackedByPieceType(getEnPassant(), getSideToMove(), PieceType.PAWN) != 0 + && verifyNotPinnedPiece(getSideToMove().flip(), getEnPassant(), getEnPassantTarget()); + } + + private boolean verifyNotPinnedPiece(Side side, Square enPassant, Square target) + { + long pawns = Attacks.getPawnAttacks(side, enPassant.getBitboard()) + & getBitboard(Piece.make(side.flip(), PieceType.PAWN)); + return pawns != 0 && verifyAllPins(pawns, side, enPassant, target); + } + + private boolean verifyAllPins(long pawns, Side side, Square enPassant, Square target) + { + long onePawn = extractLsb(pawns); + long otherPawn = pawns ^ onePawn; + if (onePawn != 0L && verifyKingIsNotAttackedWithoutPin(side, enPassant, target, onePawn)) + { + return true; + } + return verifyKingIsNotAttackedWithoutPin(side, enPassant, target, otherPawn); + } + + private boolean verifyKingIsNotAttackedWithoutPin(Side side, Square enPassant, Square target, long pawns) + { + return squareAttackedBy(getKingSquare(side.flip()), side, removePieces(enPassant, target, pawns)) == 0L; + } + + private long removePieces(Square enPassant, Square target, long pieces) + { + return (getBitboard() ^ pieces ^ target.getBitboard()) | enPassant.getBitboard(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/BoardContext.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/BoardContext.java new file mode 100644 index 0000000..0c85f7e --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/BoardContext.java @@ -0,0 +1,901 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import org.shawn.games.Serendipity.Chess.move.Move; + +import java.util.List; + +/** + * The definition of a game context, a support structure used to provide + * contextual information to a chess position, and most importantly to validate + * special moves in a uniform and consistent way according to the chess + * variation (e.g. castle moves). + */ +public class BoardContext +{ + /** + * The definition of the white king shift in the default short castle move. + */ + protected Move whiteoo; + /** + * The definition of the white king shift in the default long castle move. + */ + protected Move whiteooo; + /** + * The definition of the black king shift in the default short castle move. + */ + protected Move blackoo; + /** + * The definition of the black king shift in the default long castle move. + */ + protected Move blackooo; + + /** + * The definition of the white rook shift in the default short castle move. + */ + protected Move whiteRookoo; + /** + * The definition of the white rook shift in the default long castle move. + */ + protected Move whiteRookooo; + /** + * The definition of the black rook shift in the default short castle move. + */ + protected Move blackRookoo; + /** + * The definition of the black rook shift in the default long castle move. + */ + protected Move blackRookooo; + + /** + * The list of squares crossed by the white king in the default short castle + * move. + */ + protected List whiteooSquares; + /** + * The list of squares crossed by the white king in the default long castle + * move. + */ + protected List whiteoooSquares; + /** + * The list of squares crossed by the black king in the default short castle + * move. + */ + protected List blackooSquares; + /** + * The list of squares crossed by the black king in the default long castle + * move. + */ + protected List blackoooSquares; + + /** + * The bitboard representation of the squares crossed by the white king in the + * default short castle move. + */ + protected long whiteooSquaresBb; + /** + * The bitboard representation of the squares crossed by the white king in the + * default long castle move. + */ + protected long whiteoooSquaresBb; + /** + * The bitboard representation of the squares crossed by the black king in the + * default short castle move. + */ + protected long blackooSquaresBb; + /** + * The bitboard representation of the squares crossed by the black king in the + * default long castle move. + */ + protected long blackoooSquaresBb; + + /** + * The bitboard representation of all the squares involved in the default short + * castle move of white. + */ + protected long whiteooAllSquaresBb; + /** + * The bitboard representation of all the squares involved in the default long + * castle move of white. + */ + protected long whiteoooAllSquaresBb; + /** + * The bitboard representation of all the squares involved in the default short + * castle move of black. + */ + protected long blackooAllSquaresBb; + /** + * The bitboard representation of all the squares involved in the default long + * castle move of black. + */ + protected long blackoooAllSquaresBb; + + /** + * The initial position of the game, as a Forsyth-Edwards Notation (FEN) string. + */ + protected String startFEN; + + /** + * Constructs a new game context using the default game mode and chess + * variation. + *

+ * Same as invoking + * {@code new GameContext(GameMode.HUMAN_VS_HUMAN, VariationType.NORMAL)}. + */ + public BoardContext() + { + loadDefaults(); + } + + private static long squareListToBb(List list) + { + long r = 0L; + for (Square s : list) + { + r |= s.getBitboard(); + } + return r; + } + + private void loadDefaults() + { + // load standard values + setWhiteoo(Constants.DEFAULT_WHITE_OO); + setWhiteooo(Constants.DEFAULT_WHITE_OOO); + setBlackoo(Constants.DEFAULT_BLACK_OO); + setBlackooo(Constants.DEFAULT_BLACK_OOO); + + setWhiteRookoo(Constants.DEFAULT_WHITE_ROOK_OO); + setWhiteRookooo(Constants.DEFAULT_WHITE_ROOK_OOO); + setBlackRookoo(Constants.DEFAULT_BLACK_ROOK_OO); + setBlackRookooo(Constants.DEFAULT_BLACK_ROOK_OOO); + + setWhiteooSquares(Constants.DEFAULT_WHITE_OO_SQUARES); + setWhiteoooSquares(Constants.DEFAULT_WHITE_OOO_SQUARES); + setBlackooSquares(Constants.DEFAULT_BLACK_OO_SQUARES); + setBlackoooSquares(Constants.DEFAULT_BLACK_OOO_SQUARES); + + setWhiteooSquaresBb(squareListToBb(Constants.DEFAULT_WHITE_OO_SQUARES)); + setWhiteoooSquaresBb(squareListToBb(Constants.DEFAULT_WHITE_OOO_SQUARES)); + setBlackooSquaresBb(squareListToBb(Constants.DEFAULT_BLACK_OO_SQUARES)); + setBlackoooSquaresBb(squareListToBb(Constants.DEFAULT_BLACK_OOO_SQUARES)); + + setWhiteooAllSquaresBb(squareListToBb(Constants.DEFAULT_WHITE_OO_ALL_SQUARES)); + setWhiteoooAllSquaresBb(squareListToBb(Constants.DEFAULT_WHITE_OOO_ALL_SQUARES)); + setBlackooAllSquaresBb(squareListToBb(Constants.DEFAULT_BLACK_OO_ALL_SQUARES)); + setBlackoooAllSquaresBb(squareListToBb(Constants.DEFAULT_BLACK_OOO_ALL_SQUARES)); + + setStartFEN(Constants.startStandardFENPosition); + } + + /** + * Returns an unambiguous castle move by king given the provided side and castle + * rights, if possible. A castle move is not ambiguous if only one side of the + * board has castle rights, either king-side or queen-side (not both). + * + * @param side the side to move + * @param castleRight the castle rights available for the moving side + * @return the move representing the castle move of the king, if available and + * not ambiguous, or null otherwise + */ + public Move getKingCastleMove(Side side, CastleRight castleRight) + { + Move move = null; + + if (Side.WHITE.equals(side)) + { + if (CastleRight.KING_SIDE.equals(castleRight)) + { + move = getWhiteoo(); + } + + else if (CastleRight.QUEEN_SIDE.equals(castleRight)) + { + move = getWhiteooo(); + } + } + + else + { + if (CastleRight.KING_SIDE.equals(castleRight)) + { + move = getBlackoo(); + } + + else if (CastleRight.QUEEN_SIDE.equals(castleRight)) + { + move = getBlackooo(); + } + } + + return move; + } + + /** + * Returns an unambiguous castle move by rook given the provided side and castle + * rights, if possible. A castle move is not ambiguous if only one side of the + * board has castle rights, either king-side or queen-side (not both). + * + * @param side the side to move + * @param castleRight the castle rights available for the moving side + * @return the move representing the castle move of the rook, if available and + * not ambiguous, or null otherwise + */ + public Move getRookCastleMove(Side side, CastleRight castleRight) + { + Move move = null; + + if (Side.WHITE.equals(side)) + { + if (CastleRight.KING_SIDE.equals(castleRight)) + { + move = getWhiteRookoo(); + } + + else if (CastleRight.QUEEN_SIDE.equals(castleRight)) + { + move = getWhiteRookooo(); + } + } + + else + { + if (CastleRight.KING_SIDE.equals(castleRight)) + { + move = getBlackRookoo(); + } + + else if (CastleRight.QUEEN_SIDE.equals(castleRight)) + { + move = getBlackRookooo(); + } + } + return move; + } + + /** + * Checks if the move is a castle move or not. + * + * @param move the move to check + * @return {@code true} if the move is a castle one + */ + public boolean isCastleMove(final Move move) + { + return move.equals(getWhiteoo()) || move.equals(getWhiteooo()) || move.equals(getBlackoo()) + || move.equals(getBlackooo()); + } + + /** + * Checks if the castle move is valid according to the castle rights. + * + * @param move the move to check + * @param castleRight the castle rights to compare the move against + * @return {@code true} if the castle move is valid + */ + public boolean hasCastleRight(final Move move, final CastleRight castleRight) + { + + final CastleRight r = castleRight; + + return (CastleRight.KING_AND_QUEEN_SIDE.equals(r)) + || (move.equals(getWhiteoo()) && CastleRight.KING_SIDE.equals(r)) + || (move.equals(getBlackoo()) && CastleRight.KING_SIDE.equals(r)) + || (move.equals(getWhiteooo()) && CastleRight.QUEEN_SIDE.equals(r)) + || (move.equals(getBlackooo()) && CastleRight.QUEEN_SIDE.equals(r)); + } + + /** + * Checks if the move is a king-side (short) castle move. + * + * @param move the move to check + * @return {@code true} if the move is a king-side castle one + */ + public boolean isKingSideCastle(Move move) + { + return move.equals(getWhiteoo()) || move.equals(getBlackoo()); + } + + /** + * Checks if the move is a queen-side (long) castle move. + * + * @param move the move to check + * @return {@code true} if the move is a queen-side castle one + */ + public boolean isQueenSideCastle(Move move) + { + return move.equals(getWhiteooo()) || move.equals(getBlackooo()); + } + + /** + * Returns white king move in case of short castle. + * + * @return the short castle white king move + */ + public Move getWhiteoo() + { + return whiteoo; + } + + /** + * Sets the white king move in case of short castle. + * + * @param whiteoo the short castle white king move to set + */ + public void setWhiteoo(Move whiteoo) + { + this.whiteoo = whiteoo; + } + + /** + * Returns white king move in case of long castle. + * + * @return the long castle white king move + */ + public Move getWhiteooo() + { + return whiteooo; + } + + /** + * Sets the white king move in case of long castle. + * + * @param whiteooo the long castle white king move to set + */ + public void setWhiteooo(Move whiteooo) + { + this.whiteooo = whiteooo; + } + + /** + * Returns black king move in case of short castle. + * + * @return the short castle black king move + */ + public Move getBlackoo() + { + return blackoo; + } + + /** + * Sets the black king move in case of short castle. + * + * @param blackoo the short castle black king move to set + */ + public void setBlackoo(Move blackoo) + { + this.blackoo = blackoo; + } + + /** + * Returns black king move in case of long castle. + * + * @return the long castle black king move + */ + public Move getBlackooo() + { + return blackooo; + } + + /** + * Sets the black king move in case of long castle. + * + * @param blackooo the long castle black king move to set + */ + public void setBlackooo(Move blackooo) + { + this.blackooo = blackooo; + } + + /** + * Returns white rook move in case of short castle. + * + * @return the short castle white rook move + */ + public Move getWhiteRookoo() + { + return whiteRookoo; + } + + /** + * Sets the white rook move in case of short castle. + * + * @param whiteRookoo the short castle white rook move to set + */ + public void setWhiteRookoo(Move whiteRookoo) + { + this.whiteRookoo = whiteRookoo; + } + + /** + * Returns white rook move in case of long castle. + * + * @return the long castle white rook move + */ + public Move getWhiteRookooo() + { + return whiteRookooo; + } + + /** + * Sets the white rook move in case of long castle. + * + * @param whiteRookooo the long castle white rook move to set + */ + public void setWhiteRookooo(Move whiteRookooo) + { + this.whiteRookooo = whiteRookooo; + } + + /** + * Returns black rook move in case of short castle. + * + * @return the short castle black rook move + */ + public Move getBlackRookoo() + { + return blackRookoo; + } + + /** + * Sets the black rook move in case of short castle. + * + * @param blackRookoo the short castle black rook move to set + */ + public void setBlackRookoo(Move blackRookoo) + { + this.blackRookoo = blackRookoo; + } + + /** + * Returns black rook move in case of long castle. + * + * @return the long castle black rook move + */ + public Move getBlackRookooo() + { + return blackRookooo; + } + + /** + * Sets the black rook move in case of long castle. + * + * @param blackRookooo the long castle black rook move to set + */ + public void setBlackRookooo(Move blackRookooo) + { + this.blackRookooo = blackRookooo; + } + + /** + * Returns the initial position of the game as a Forsyth-Edwards Notation (FEN) + * string. + * + * @return the initial position in FEN notation + */ + public String getStartFEN() + { + return startFEN; + } + + /** + * Sets the initial position of the game, provided as a Forsyth-Edwards Notation + * (FEN). + * + * @param startFEN the initial position to set + */ + public void setStartFEN(String startFEN) + { + this.startFEN = startFEN; + } + + /** + * Returns the list of squares crossed by the white king in the short castle + * move. + * + * @return the squares crossed by the white king in the short castle move + */ + public List getWhiteooSquares() + { + return whiteooSquares; + } + + /** + * Sets the list of squares crossed by the white king in the short castle move. + * + * @param whiteooSquares the list of squares to set + */ + public void setWhiteooSquares(List whiteooSquares) + { + this.whiteooSquares = whiteooSquares; + } + + /** + * Returns the list of squares crossed by the white king in the long castle + * move. + * + * @return the squares crossed by the white king in the long castle move + */ + public List getWhiteoooSquares() + { + return whiteoooSquares; + } + + /** + * Sets the list of squares crossed by the white king in the long castle move. + * + * @param whiteoooSquares the list of squares to set + */ + public void setWhiteoooSquares(List whiteoooSquares) + { + this.whiteoooSquares = whiteoooSquares; + } + + /** + * Returns the list of squares crossed by the black king in the short castle + * move. + * + * @return the squares crossed by the black king in the short castle move + */ + public List getBlackooSquares() + { + return blackooSquares; + } + + /** + * Sets the list of squares crossed by the black king in the short castle move. + * + * @param blackooSquares the list of squares to set + */ + public void setBlackooSquares(List blackooSquares) + { + this.blackooSquares = blackooSquares; + } + + /** + * Returns the list of squares crossed by the black king in the long castle + * move. + * + * @return the squares crossed by the black king in the long castle move + */ + public List getBlackoooSquares() + { + return blackoooSquares; + } + + /** + * Sets the list of squares crossed by the black king in the long castle move. + * + * @param blackoooSquares the list of squares to set + */ + public void setBlackoooSquares(List blackoooSquares) + { + this.blackoooSquares = blackoooSquares; + } + + /** + * Returns the bitboard representation of the squares crossed by the white king + * in the short castle move. + * + * @return the bitboard representing the squares crossed by the white king in + * the short castle move + */ + public long getWhiteooSquaresBb() + { + return whiteooSquaresBb; + } + + /** + * Sets the bitboard representation of the squares crossed by the white king in + * the short castle move. + * + * @param whiteooSquaresBb the bitboard to set + */ + public void setWhiteooSquaresBb(long whiteooSquaresBb) + { + this.whiteooSquaresBb = whiteooSquaresBb; + } + + /** + * Returns the bitboard representation of the squares crossed by the white king + * in the long castle move. + * + * @return the bitboard representing the squares crossed by the white king in + * the long castle move + */ + public long getWhiteoooSquaresBb() + { + return whiteoooSquaresBb; + } + + /** + * Sets the bitboard representation of the squares crossed by the white king in + * the long castle move. + * + * @param whiteoooSquaresBb the bitboard to set + */ + public void setWhiteoooSquaresBb(long whiteoooSquaresBb) + { + this.whiteoooSquaresBb = whiteoooSquaresBb; + } + + /** + * Returns the bitboard representation of the squares crossed by the black king + * in the short castle move. + * + * @return the bitboard representing the squares crossed by the black king in + * the short castle move + */ + public long getBlackooSquaresBb() + { + return blackooSquaresBb; + } + + /** + * Sets the bitboard representation of the squares crossed by the black king in + * the short castle move. + * + * @param blackooSquaresBb the bitboard to set + */ + public void setBlackooSquaresBb(long blackooSquaresBb) + { + this.blackooSquaresBb = blackooSquaresBb; + } + + /** + * Returns the bitboard representation of the squares crossed by the black king + * in the long castle move. + * + * @return the bitboard representing the squares crossed by the black king in + * the long castle move + */ + public long getBlackoooSquaresBb() + { + return blackoooSquaresBb; + } + + /** + * Sets the bitboard representation of the squares crossed by the black king in + * the long castle move. + * + * @param blackoooSquaresBb the bitboard to set + */ + public void setBlackoooSquaresBb(long blackoooSquaresBb) + { + this.blackoooSquaresBb = blackoooSquaresBb; + } + + /** + * Returns the bitboard representation of all the squares involved in the short + * castle move of white. + * + * @return the bitboard representing the squares involved in the short castle + * move of white + */ + public long getWhiteooAllSquaresBb() + { + return whiteooAllSquaresBb; + } + + /** + * Sets the bitboard representation of all the squares involved in the short + * castle move of white. + * + * @param whiteooAllSquaresBb the bitboard to set + * @return this game context instance + */ + public BoardContext setWhiteooAllSquaresBb(long whiteooAllSquaresBb) + { + this.whiteooAllSquaresBb = whiteooAllSquaresBb; + return this; + } + + /** + * Returns the bitboard representation of all the squares involved in the long + * castle move of white. + * + * @return the bitboard representing the squares involved in the long castle + * move of white + */ + public long getWhiteoooAllSquaresBb() + { + return whiteoooAllSquaresBb; + } + + /** + * Sets the bitboard representation of all the squares involved in the long + * castle move of white. + * + * @param whiteoooAllSquaresBb the bitboard to set + * @return this game context instance + */ + public BoardContext setWhiteoooAllSquaresBb(long whiteoooAllSquaresBb) + { + this.whiteoooAllSquaresBb = whiteoooAllSquaresBb; + return this; + } + + /** + * Returns the bitboard representation of all the squares involved in the short + * castle move of black. + * + * @return the bitboard representing the squares involved in the short castle + * move of black + */ + public long getBlackooAllSquaresBb() + { + return blackooAllSquaresBb; + } + + /** + * Sets the bitboard representation of all the squares involved in the short + * castle move of black. + * + * @param blackooAllSquaresBb the bitboard to set + * @return this game context instance + */ + public BoardContext setBlackooAllSquaresBb(long blackooAllSquaresBb) + { + this.blackooAllSquaresBb = blackooAllSquaresBb; + return this; + } + + /** + * Returns the bitboard representation of all the squares involved in the long + * castle move of black. + * + * @return the bitboard representing the squares involved in the long castle + * move of black + */ + public long getBlackoooAllSquaresBb() + { + return blackoooAllSquaresBb; + } + + /** + * Sets the bitboard representation of all the squares involved in the long + * castle move of black. + * + * @param blackoooAllSquaresBb the bitboard to set + * @return this game context instance + */ + public BoardContext setBlackoooAllSquaresBb(long blackoooAllSquaresBb) + { + this.blackoooAllSquaresBb = blackoooAllSquaresBb; + return this; + } + + /** + * Returns the short castle king move based on the side to move. + * + * @param side the side to move + * @return the short castle king move + */ + public Move getoo(Side side) + { + return Side.WHITE.equals(side) ? getWhiteoo() : getBlackoo(); + } + + /** + * Returns the long castle king move based on the side to move. + * + * @param side the side to move + * @return the long castle king move + */ + public Move getooo(Side side) + { + return Side.WHITE.equals(side) ? getWhiteooo() : getBlackooo(); + } + + /** + * Returns the short castle rook move based on the side to move. + * + * @param side the side to move + * @return the short castle rook move + */ + public Move getRookoo(Side side) + { + return Side.WHITE.equals(side) ? getWhiteRookoo() : getBlackRookoo(); + } + + /** + * Returns the long castle rook move based on the side to move. + * + * @param side the side to move + * @return the long castle rook move + */ + public Move getRookooo(Side side) + { + return Side.WHITE.equals(side) ? getWhiteRookooo() : getBlackRookooo(); + } + + /** + * Returns the list of squares crossed by the king in the short castle move + * based on the side to move. + * + * @param side the side to move + * @return the squares crossed by the king in the short castle move + */ + public List getooSquares(Side side) + { + return Side.WHITE.equals(side) ? getWhiteooSquares() : getBlackooSquares(); + } + + /** + * Returns the list of squares crossed by the king in the long castle move based + * on the side to move. + * + * @param side the side to move + * @return the squares crossed by the king in the long castle move + */ + public List getoooSquares(Side side) + { + return Side.WHITE.equals(side) ? getWhiteoooSquares() : getBlackoooSquares(); + } + + /** + * Returns the bitboard representation of the squares crossed by the king in the + * short castle move based on the side to move. + * + * @param side the side to move + * @return the bitboard representing the squares crossed by the king in the + * short castle move + */ + public long getooSquaresBb(Side side) + { + return Side.WHITE.equals(side) ? getWhiteooSquaresBb() : getBlackooSquaresBb(); + } + + /** + * Returns the bitboard representation of the squares crossed by the king in the + * long castle move based on the side to move. + * + * @param side the side to move + * @return the bitboard representing the squares crossed by the king in the long + * castle move + */ + public long getoooSquaresBb(Side side) + { + return Side.WHITE.equals(side) ? getWhiteoooSquaresBb() : getBlackoooSquaresBb(); + } + + /** + * Returns the bitboard representation of all the squares involved in the short + * castle move based on the side to move. + * + * @param side the side to move + * @return the bitboard representing the squares involved in the short castle + * move + */ + public long getooAllSquaresBb(Side side) + { + return Side.WHITE.equals(side) ? getWhiteooAllSquaresBb() : getBlackooAllSquaresBb(); + } + + /** + * Returns the bitboard representation of all the squares involved in the long + * castle move based on the side to move. + * + * @param side the side to move + * @return the bitboard representing the squares involved in the long castle + * move + */ + public long getoooAllSquaresBb(Side side) + { + return Side.WHITE.equals(side) ? getWhiteoooAllSquaresBb() : getBlackoooAllSquaresBb(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/CastleRight.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/CastleRight.java new file mode 100644 index 0000000..8a14f60 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/CastleRight.java @@ -0,0 +1,67 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +/** + * The different combinations of castle rights for a side in a chess game. A + * side can castle only king-side (short castle), only queen-side (long castle), + * both, or neither king-side nor queen-side. + */ +public enum CastleRight +{ + /** + * The king-side castle right (short castle). + */ + KING_SIDE, + /** + * The queen-side castle right (long castle). + */ + QUEEN_SIDE, + /** + * Both king and queen-side castle right. + */ + KING_AND_QUEEN_SIDE, + /** + * No castle right, i.e. it is no possible to castle. + */ + NONE; + + /** + * Returns a castle right given its name. + *

+ * Same as invoking {@link CastleRight#valueOf(String)}. + * + * @param v name of the castle right + * @return the castle right with the specified name + * @throws IllegalArgumentException if the name does not correspond to any + * castle right + */ + public static CastleRight fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the name of the castle right. + * + * @return the name of the castle right + */ + public String value() + { + return name(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Constants.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Constants.java new file mode 100644 index 0000000..051e05a --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Constants.java @@ -0,0 +1,133 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import java.util.ArrayList; +import java.util.List; + +import org.shawn.games.Serendipity.Chess.move.Move; + +/** + * A handy collection of constant values to be used in common scenarios. + */ +public class Constants +{ + /** + * The FEN definition of the standard starting position. + */ + public static final String startStandardFENPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + /** + * The shift of the white king in a default short castle move. + */ + public static final Move DEFAULT_WHITE_OO = new Move(Square.E1, Square.G1); + /** + * The shift of the white king in a default long castle move. + */ + public static final Move DEFAULT_WHITE_OOO = new Move(Square.E1, Square.C1); + /** + * The shift of the black king in a default short castle move. + */ + public static final Move DEFAULT_BLACK_OO = new Move(Square.E8, Square.G8); + /** + * The shift of the black king in a default long castle move. + */ + public static final Move DEFAULT_BLACK_OOO = new Move(Square.E8, Square.C8); + /** + * The shift of the white rook in a default short castle move. + */ + public static final Move DEFAULT_WHITE_ROOK_OO = new Move(Square.H1, Square.F1); + /** + * The shift of the white rook in a default long castle move. + */ + public static final Move DEFAULT_WHITE_ROOK_OOO = new Move(Square.A1, Square.D1); + /** + * The shift of the black rook in a default short castle move. + */ + public static final Move DEFAULT_BLACK_ROOK_OO = new Move(Square.H8, Square.F8); + /** + * The shift of the black rook in a default long castle move. + */ + public static final Move DEFAULT_BLACK_ROOK_OOO = new Move(Square.A8, Square.D8); + /** + * The list of squares crossed by the white king in the case of short castle. + */ + public static final List DEFAULT_WHITE_OO_SQUARES = new ArrayList(); + /** + * The list of squares crossed by the white king in the case of long castle. + */ + public static final List DEFAULT_WHITE_OOO_SQUARES = new ArrayList(); + /** + * The list of squares crossed by the black king in the case of short castle. + */ + public static final List DEFAULT_BLACK_OO_SQUARES = new ArrayList(); + /** + * The list of squares crossed by the black king in the case of long castle. + */ + public static final List DEFAULT_BLACK_OOO_SQUARES = new ArrayList(); + + /** + * The list of all squares involved in the case of short castle of white. + */ + public static final List DEFAULT_WHITE_OO_ALL_SQUARES = new ArrayList(); + /** + * The list of all squares involved in the case of long castle of white. + */ + public static final List DEFAULT_WHITE_OOO_ALL_SQUARES = new ArrayList(); + /** + * The list of all squares involved in the case of short castle of black. + */ + public static final List DEFAULT_BLACK_OO_ALL_SQUARES = new ArrayList(); + /** + * The list of all squares involved in the case of long castle of black. + */ + public static final List DEFAULT_BLACK_OOO_ALL_SQUARES = new ArrayList(); + + /** + * A useful special value that represents an empty move, that is, a move that + * does nothing and leaves the board unchanged. + */ + public static final Move emptyMove = new Move(Square.NONE, Square.NONE); + + static + { + DEFAULT_WHITE_OO_SQUARES.add(Square.F1); + DEFAULT_WHITE_OO_SQUARES.add(Square.G1); + DEFAULT_WHITE_OOO_SQUARES.add(Square.D1); + DEFAULT_WHITE_OOO_SQUARES.add(Square.C1); + + DEFAULT_BLACK_OO_SQUARES.add(Square.F8); + DEFAULT_BLACK_OO_SQUARES.add(Square.G8); + DEFAULT_BLACK_OOO_SQUARES.add(Square.D8); + DEFAULT_BLACK_OOO_SQUARES.add(Square.C8); + + DEFAULT_WHITE_OO_ALL_SQUARES.add(Square.F1); + DEFAULT_WHITE_OO_ALL_SQUARES.add(Square.G1); + DEFAULT_WHITE_OOO_ALL_SQUARES.add(Square.D1); + DEFAULT_WHITE_OOO_ALL_SQUARES.add(Square.C1); + DEFAULT_WHITE_OOO_ALL_SQUARES.add(Square.B1); + + DEFAULT_BLACK_OO_ALL_SQUARES.add(Square.F8); + DEFAULT_BLACK_OO_ALL_SQUARES.add(Square.G8); + DEFAULT_BLACK_OOO_ALL_SQUARES.add(Square.D8); + DEFAULT_BLACK_OOO_ALL_SQUARES.add(Square.C8); + DEFAULT_BLACK_OOO_ALL_SQUARES.add(Square.B8); + } + + private Constants() + { + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/File.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/File.java new file mode 100644 index 0000000..bbdeeda --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/File.java @@ -0,0 +1,109 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import org.apache.commons.lang3.StringUtils; + +/** + * The files in a board. A file is a column in the chessboard, and it is + * identified as a letter from {@code A} to {@code H}. + *

+ * Each value defines a single file, except for the special value + * {@link File#NONE} which represents no file. + */ +public enum File +{ + /** + * The {@code A} file. + */ + FILE_A("A"), + /** + * The {@code B} file. + */ + FILE_B("B"), + /** + * The {@code C} file. + */ + FILE_C("C"), + /** + * The {@code D} file. + */ + FILE_D("D"), + /** + * The {@code E} file. + */ + FILE_E("E"), + /** + * The {@code F} file. + */ + FILE_F("F"), + /** + * The {@code G} file. + */ + FILE_G("G"), + /** + * The {@code H} file. + */ + FILE_H("H"), + /** + * Special value that represents no file in particular. + */ + NONE(StringUtils.EMPTY); + + public static final File[] allFiles = values(); + + final String notation; + + File(String notation) + { + this.notation = notation; + } + + /** + * Returns a file given its name. + *

+ * Same as invoking {@link File#valueOf(String)}. + * + * @param v name of the file + * @return the file with the specified name + * @throws IllegalArgumentException if the name does not correspond to any file + */ + public static File fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the letter that identifies the file in chess notations. + * + * @return the letter used to represent the file + */ + public String getNotation() + { + return notation; + } + + /** + * Returns the name of the file. + * + * @return the name of the file + */ + public String value() + { + return name(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/MoveBackup.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/MoveBackup.java new file mode 100644 index 0000000..c813e80 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/MoveBackup.java @@ -0,0 +1,445 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import static org.shawn.games.Serendipity.Chess.Constants.emptyMove; + +import java.util.EnumMap; + +import org.shawn.games.Serendipity.Chess.move.Move; + +/** + * A structure that can be used to cancel the effects of a move and to restore + * the board to a previous status. The board context is memorized at the + * backup is created, and it could be subsequently re-applied to the + * sourcing board. + *

+ * The move backup is also a {@link BoardEvent}, and hence it can be passed to + * the observers of the {@link BoardEventType#ON_UNDO_MOVE} events, emitted when + * a move is reverted on a board. + */ +public class MoveBackup +{ + private final EnumMap castleRight; + private Side sideToMove; + private Square enPassantTarget; + private Square enPassant; + private Integer moveCounter; + private Integer halfMoveCounter; + private Move move; + private Move rookCastleMove; + private Piece capturedPiece; + private Square capturedSquare; + private Piece movingPiece; + private boolean castleMove; + private boolean enPassantMove; + private long incrementalHashKey; + + /** + * Constructs a new empty move backup. + */ + public MoveBackup() + { + castleRight = new EnumMap<>(Side.class); + } + + /** + * Constructs a new move backup taking a board and a move. At the same time, it + * both instantiates the data structure and takes a snapshot of the board status + * for a later restore. + * + * @param board the board that describes the status at the time of the move + * @param move the move which could be potentially restored later in time + */ + public MoveBackup(Board board, Move move) + { + this(); + makeBackup(board, move); + } + + /** + * Initiates a new move backup, possibly overwriting any previously existing + * backup. + * + * @param board the board that describes the status at the time of the move + * @param move the move which could be potentially restored later in time + */ + public void makeBackup(Board board, Move move) + { + setIncrementalHashKey(board.getIncrementalHashKey()); + setSideToMove(board.getSideToMove()); + setEnPassantTarget(board.getEnPassantTarget()); + setEnPassant(board.getEnPassant()); + setMoveCounter(board.getMoveCounter()); + setHalfMoveCounter(board.getHalfMoveCounter()); + setMove(move); + getCastleRight().put(Side.WHITE, board.getCastleRight(Side.WHITE)); + getCastleRight().put(Side.BLACK, board.getCastleRight(Side.BLACK)); + setCapturedPiece(board.getPiece(move.getTo())); + setCapturedSquare(move.getTo()); + Piece moving = board.getPiece(move.getFrom()); + setMovingPiece(moving); + if (board.getContext().isCastleMove(move) && movingPiece == Piece.make(board.getSideToMove(), PieceType.KING)) + { + CastleRight c = board.getContext().isKingSideCastle(move) ? CastleRight.KING_SIDE : CastleRight.QUEEN_SIDE; + Move rookMove = board.getContext().getRookCastleMove(board.getSideToMove(), c); + setRookCastleMove(rookMove); + setCastleMove(true); + } + else + { + setRookCastleMove(null); + setCastleMove(false); + } + } + + /** + * Restores the previously stored status backup to the board passed as an + * argument, effectively cancelling the consequences of the move memorized at + * the time the backup was created, as well as any potential move executed on + * the board after that moment. + *

+ * It is a responsibility of the caller to make sure the board used for creating + * the backup is also the board passed in input to this method. No check is + * performed to prevent another board is used instead. + * + * @param board the board to be restored to a previous status + */ + public void restore(Board board) + { + board.setSideToMove(getSideToMove()); + board.setEnPassantTarget(getEnPassantTarget()); + board.setEnPassant(getEnPassant()); + board.setMoveCounter(getMoveCounter()); + board.setHalfMoveCounter(getHalfMoveCounter()); + Piece movingPiece = move.getPromotion() == Piece.NONE ? getMovingPiece() : move.getPromotion(); + board.getCastleRight().put(Side.WHITE, getCastleRight().get(Side.WHITE)); + board.getCastleRight().put(Side.BLACK, getCastleRight().get(Side.BLACK)); + + if (move != emptyMove) + { + final boolean isCastle = board.getContext().isCastleMove(getMove()); + + if (PieceType.KING.equals(movingPiece.getPieceType()) && isCastle) + { + board.undoMovePiece(getRookCastleMove()); + } + board.unsetPiece(movingPiece, getMove().getTo()); + if (Piece.NONE.equals(getMove().getPromotion())) + { + board.setPiece(movingPiece, getMove().getFrom()); + } + else + { + board.setPiece(Piece.make(getSideToMove(), PieceType.PAWN), getMove().getFrom()); + } + if (!Piece.NONE.equals(getCapturedPiece())) + { + board.setPiece(getCapturedPiece(), getCapturedSquare()); + } + } + + board.setIncrementalHashKey(getIncrementalHashKey()); + } + + /** + * Returns the next side to move used for restoring the board. + * + * @return the next side to move + */ + public Side getSideToMove() + { + return sideToMove; + } + + /** + * Sets the next side to move used for restoring the board. + * + * @param sideToMove the next side to move + */ + public void setSideToMove(Side sideToMove) + { + this.sideToMove = sideToMove; + } + + /** + * Returns the target square of an en passant capture used for restoring the + * board. + * + * @return the en passant target square, or {@link Square#NONE} if en passant + * was not possible at the time the backup was created + */ + public Square getEnPassantTarget() + { + return enPassantTarget; + } + + /** + * Sets the target square of an en passant capture used for restoring the board. + * + * @param enPassant the en passant target square + */ + public void setEnPassantTarget(Square enPassant) + { + this.enPassantTarget = enPassant; + } + + /** + * Returns the destination square of an en passant capture used for restoring + * the board. + * + * @return the en passant destination square, or {@link Square#NONE} if en + * passant was not possible at the time the backup was created + */ + public Square getEnPassant() + { + return enPassant; + } + + /** + * Sets the destination square of an en passant capture used for restoring the + * board. + * + * @param enPassant the en passant destination square + */ + public void setEnPassant(Square enPassant) + { + this.enPassant = enPassant; + } + + /** + * Returns the counter of full moves used for restoring the board. + * + * @return the counter of full moves + */ + public Integer getMoveCounter() + { + return moveCounter; + } + + /** + * Sets the counter of full moves used for restoring the board. + * + * @param moveCounter the counter of full moves + */ + public void setMoveCounter(Integer moveCounter) + { + this.moveCounter = moveCounter; + } + + /** + * Returns the counter of half moves used for restoring the board. + * + * @return the counter of half moves + */ + public Integer getHalfMoveCounter() + { + return halfMoveCounter; + } + + /** + * Sets the counter of half moves used for restoring the board. + * + * @param halfMoveCounter the counter of half moves + */ + public void setHalfMoveCounter(Integer halfMoveCounter) + { + this.halfMoveCounter = halfMoveCounter; + } + + /** + * Returns the move to revert in the case a board has to be restored. + * + * @return the move to revert + */ + public Move getMove() + { + return move; + } + + /** + * Sets the move to revert in the case a board has to be restored. + * + * @param move the move to revert + */ + public void setMove(Move move) + { + this.move = move; + } + + /** + * Returns the rook move to apply in order to revert a castle move in the case a + * board has to be restored. + * + * @return the rook move to apply to revert a castle move, or null if the move + * to revert is not a castle move + */ + public Move getRookCastleMove() + { + return rookCastleMove; + } + + /** + * Sets the rook move to apply in order to revert a castle move in the case a + * board has to be restored. + * + * @param rookCastleMove the rook move to apply to revert a castle move + */ + public void setRookCastleMove(Move rookCastleMove) + { + this.rookCastleMove = rookCastleMove; + } + + /** + * Returns the castle rights used for restoring the board. + * + * @return the castle rights + */ + public EnumMap getCastleRight() + { + return castleRight; + } + + /** + * Returns the piece captured with the move to revert in the case a board has to + * be restored. + * + * @return the captured piece, or {@link Piece#NONE} if no piece was captured at + * the time the backup was created + */ + public Piece getCapturedPiece() + { + return capturedPiece; + } + + /** + * Sets the captured piece used for restoring the board. + * + * @param capturedPiece the captured piece + */ + public void setCapturedPiece(Piece capturedPiece) + { + this.capturedPiece = capturedPiece; + } + + /** + * Returns the square of the piece captured with the move to revert in the case + * a board has to be restored. + * + * @return the square of the captured piece, or {@link Square#NONE} if no piece + * was captured at the time the backup was created + */ + public Square getCapturedSquare() + { + return capturedSquare; + } + + /** + * Sets the square of the captured piece used for restoring the board. + * + * @param capturedSquare the square of the captured piece + */ + public void setCapturedSquare(Square capturedSquare) + { + this.capturedSquare = capturedSquare; + } + + /** + * Returns the piece moved in the move to revert in the case a board has to be + * restored. + * + * @return the moved piece + */ + public Piece getMovingPiece() + { + return movingPiece; + } + + /** + * Sets the moving piece used for restoring the board. + * + * @param movingPiece the moving piece + */ + public void setMovingPiece(Piece movingPiece) + { + this.movingPiece = movingPiece; + } + + /** + * Checks if the move to revert in the case a board has to be restored is a + * castle move. + * + * @return {@code true} if the move is a castle move + */ + public boolean isCastleMove() + { + return castleMove; + } + + /** + * Sets whether the move to revert in the case a board has to be restored is a + * castle move or not. + * + * @param castleMove whether the move to restore is a castle move or not + */ + public void setCastleMove(boolean castleMove) + { + this.castleMove = castleMove; + } + + /** + * Checks if the move to revert in the case a board has to be restored is an en + * passant move. + * + * @return {@code true} if the move is an en passant move + */ + public boolean isEnPassantMove() + { + return enPassantMove; + } + + /** + * Sets whether the move to revert in the case a board has to be restored is an + * en passant move or not. + * + * @param enPassantMove whether the move to restore is an en passant move or not + */ + public void setEnPassantMove(boolean enPassantMove) + { + this.enPassantMove = enPassantMove; + } + + /** + * Returns the incremental hash key used for restoring the board. + * + * @return the incremental hash key + */ + public long getIncrementalHashKey() + { + return incrementalHashKey; + } + + /** + * Sets the incremental hash key used for restoring the board. + * + * @param incrementalHashKey the incremental hash key + */ + public void setIncrementalHashKey(long incrementalHashKey) + { + this.incrementalHashKey = incrementalHashKey; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Piece.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Piece.java new file mode 100644 index 0000000..1e1e4e0 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Piece.java @@ -0,0 +1,223 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import java.util.HashMap; +import java.util.Map; + +/** + * A chess piece on the board, that is, a specific combination of a {@link Side} + * and a {@link PieceType}. + *

+ * Each value defines a single piece, except for the special value + * {@link Piece#NONE} which identifies that no piece is selected or assigned. + */ +public enum Piece +{ + /** + * A white pawn. + */ + WHITE_PAWN(Side.WHITE, PieceType.PAWN, "♙", "P"), + /** + * A white knight. + */ + WHITE_KNIGHT(Side.WHITE, PieceType.KNIGHT, "♘", "N"), + /** + * A white bishop. + */ + WHITE_BISHOP(Side.WHITE, PieceType.BISHOP, "♗", "B"), + /** + * A white rook. + */ + WHITE_ROOK(Side.WHITE, PieceType.ROOK, "♖", "R"), + /** + * A white queen. + */ + WHITE_QUEEN(Side.WHITE, PieceType.QUEEN, "♕", "Q"), + /** + * A white king. + */ + WHITE_KING(Side.WHITE, PieceType.KING, "♔", "K"), + /** + * A black pawn. + */ + BLACK_PAWN(Side.BLACK, PieceType.PAWN, "♟", "p"), + /** + * A black knight. + */ + BLACK_KNIGHT(Side.BLACK, PieceType.KNIGHT, "♞", "n"), + /** + * A black bishop. + */ + BLACK_BISHOP(Side.BLACK, PieceType.BISHOP, "♝", "b"), + /** + * A black rook. + */ + BLACK_ROOK(Side.BLACK, PieceType.ROOK, "♜", "r"), + /** + * A black queen. + */ + BLACK_QUEEN(Side.BLACK, PieceType.QUEEN, "♛", "q"), + /** + * A black king. + */ + BLACK_KING(Side.BLACK, PieceType.KING, "♚", "k"), + /** + * Special value that represents no piece in particular. + */ + NONE(null, null, "NONE", "."); + + public static final Piece[] allPieces = values(); + private static final Map fenToPiece = new HashMap<>(13); + private static final Piece[][] pieceMake = { { WHITE_PAWN, BLACK_PAWN }, { WHITE_KNIGHT, BLACK_KNIGHT }, + { WHITE_BISHOP, BLACK_BISHOP }, { WHITE_ROOK, BLACK_ROOK }, { WHITE_QUEEN, BLACK_QUEEN }, + { WHITE_KING, BLACK_KING }, { NONE, NONE }, }; + + static + { + for (final Piece piece : Piece.values()) + { + fenToPiece.put(piece.getFenSymbol(), piece); + } + } + + private final Side side; + private final PieceType type; + private final String fanSymbol; + private final String fenSymbol; + + Piece(Side side, PieceType type, String fanSymbol, String fenSymbol) + { + this.side = side; + this.type = type; + this.fanSymbol = fanSymbol; + this.fenSymbol = fenSymbol; + } + + /** + * Returns a piece given its name. + *

+ * Same as invoking {@link Piece#valueOf(String)}. + * + * @param v name of the piece + * @return the piece with the specified name + * @throws IllegalArgumentException if the name does not correspond to any piece + */ + public static Piece fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the piece corresponding to the provided pair of side and type. If + * {@link PieceType#NONE} is requested, {@link Piece#NONE} is returned + * regardless of the side. + * + * @param side the side of the wanted piece + * @param type the type of the wanted piece + * @return the piece corresponding to the given combination of side and type + */ + public static Piece make(Side side, PieceType type) + { + return pieceMake[type.ordinal()][side.ordinal()]; + } + + /** + * Returns the piece corresponding to the given Forsyth-Edwards Notation (FEN) + * symbol. + * + * @param fenSymbol a piece FEN symbol, such as {@code K}, {@code b} or + * {@code p} + * @return the piece that corresponds to the FEN symbol provided in input + * @throws IllegalArgumentException if the input symbol does not correspond to + * any standard chess piece + */ + public static Piece fromFenSymbol(String fenSymbol) + { + final Piece piece = fenToPiece.get(fenSymbol); + if (piece == null) + { + throw new IllegalArgumentException(String.format("Unknown piece '%s'", fenSymbol)); + } + return piece; + } + + /** + * Returns the name of the piece. + * + * @return the name of the piece + */ + public String value() + { + return name(); + } + + /** + * Returns the type of this piece. + * + * @return the piece type of this piece + */ + public PieceType getPieceType() + { + return type; + } + + /** + * Returns the side of this piece. + * + * @return the side of this piece + */ + public Side getPieceSide() + { + return side; + } + + /** + * Returns the Short Algebraic Notation (SAN) symbol for this piece. For + * example, {@code R} for a rook, {@code K} for a king, or an empty string for a + * pawn. + * + * @return the SAN symbol of this piece + */ + public String getSanSymbol() + { + return type.getSanSymbol(); + } + + /** + * Returns the Figurine Algebraic Notation (FAN) symbol for this piece. For + * example, {@code ♜} for a black rook, or {@code ♙} for a white pawn. + * + * @return the FAN symbol of this piece + */ + public String getFanSymbol() + { + return fanSymbol; + } + + /** + * Returns the Forsyth-Edwards Notation (FEN) symbol for this piece. For + * example, {@code r} for a black rook, or {@code P} for a white pawn. + * + * @return the FEN symbol of this piece + */ + public String getFenSymbol() + { + return fenSymbol; + } + +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/PieceType.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/PieceType.java new file mode 100644 index 0000000..8940bd5 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/PieceType.java @@ -0,0 +1,145 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * All possible piece types in a chess game. + *

+ * Each value defines a single piece type, except for the special value + * {@link PieceType#NONE} which represents no type in particular. + */ +public enum PieceType +{ + /** + * The pawn piece type. + */ + PAWN(StringUtils.EMPTY), + /** + * The knight piece type. + */ + KNIGHT("N"), + /** + * The bishop piece type. + */ + BISHOP("B"), + /** + * The rook piece type. + */ + ROOK("R"), + /** + * The queen piece type. + */ + QUEEN("Q"), + /** + * The king piece type. + */ + KING("K"), + /** + * Special value that represents no piece type in particular. + */ + NONE("NONE"); + + private static final Map sanToType = new HashMap<>(7); + private static final PieceType[] validValues = new PieceType[] { PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; + + static + { + for (final PieceType type : PieceType.values()) + { + sanToType.put(type.getSanSymbol(), type); + } + } + + private final String sanSymbol; + + PieceType(String sanSymbol) + { + this.sanSymbol = sanSymbol; + } + + /** + * Returns a piece type given its name. + *

+ * Same as invoking {@link PieceType#valueOf(String)}. + * + * @param v name of the piece type + * @return the piece type with the specified name + * @throws IllegalArgumentException if the name does not correspond to any piece + * type + */ + public static PieceType fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the piece type corresponding to the given Short Algebraic Notation + * (SAN) symbol. + * + * @param sanSymbol a piece symbol in SAN notation, such as {@code K} or + * {@code B}, or the empty string for the pawn type + * @return the piece type that corresponds to the SAN symbol provided in input + * @throws IllegalArgumentException if the input symbol does not correspond to + * any standard chess piece type + */ + public static PieceType fromSanSymbol(String sanSymbol) + { + final PieceType pieceType = sanToType.get(sanSymbol); + if (pieceType == null) + { + throw new IllegalArgumentException(String.format("Unknown piece '%s'", sanSymbol)); + } + return pieceType; + } + + /** + * Returns the Short Algebraic Notation (SAN) symbol for this piece type. For + * example, {@code R} for the rook type, {@code K} for the king type, or an + * empty string for the pawn type. + * + * @return the SAN symbol of this piece type + */ + public String getSanSymbol() + { + return sanSymbol; + } + + /** + * Returns the name of the piece type. + * + * @return the name of the piece type + */ + public String value() + { + return name(); + } + + /** + * Returns an array of valid piece types. + * + * @return the array of valid piece types + */ + public static PieceType[] validValues() + { + return validValues; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Rank.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Rank.java new file mode 100644 index 0000000..c1f492b --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Rank.java @@ -0,0 +1,109 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import org.apache.commons.lang3.StringUtils; + +/** + * The ranks in a board. A rank is a raw in the chessboard, and it is + * identified as a number from 1 to 8. + *

+ * Each value defines a single rank, except for the special value + * {@link Rank#NONE} which represents no rank. + */ +public enum Rank +{ + /** + * The 1st rank. + */ + RANK_1("1"), + /** + * The 2nd rank. + */ + RANK_2("2"), + /** + * The 3rd rank. + */ + RANK_3("3"), + /** + * The 4th rank. + */ + RANK_4("4"), + /** + * The 5th rank. + */ + RANK_5("5"), + /** + * The 6th rank. + */ + RANK_6("6"), + /** + * The 7th rank. + */ + RANK_7("7"), + /** + * The 8th rank. + */ + RANK_8("8"), + /** + * Special value that represents no rank in particular. + */ + NONE(StringUtils.EMPTY); + + public static final Rank[] allRanks = values(); + + final String notation; + + Rank(String notation) + { + this.notation = notation; + } + + /** + * Returns a rank given its name. + *

+ * Same as invoking {@link Rank#valueOf(String)}. + * + * @param v name of the rank + * @return the rank with the specified name + * @throws IllegalArgumentException if the name does not correspond to any rank + */ + public static Rank fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the number that identifies the rank in chess notations. + * + * @return the number used to represent the rank, as a string + */ + public String getNotation() + { + return notation; + } + + /** + * Returns the name of the rank. + * + * @return the name of the rank + */ + public String value() + { + return name(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Side.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Side.java new file mode 100644 index 0000000..e3315e4 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Side.java @@ -0,0 +1,69 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +/** + * One of the two sides in a chess game, {@link Side#WHITE} or + * {@link Side#BLACK}. + */ +public enum Side +{ + /** + * The white side. + */ + WHITE, + /** + * The black side. + */ + BLACK; + + public static final Side[] allSides = values(); + + /** + * Returns a side given its name. + *

+ * Same as invoking {@link Side#valueOf(String)}. + * + * @param v name of the side + * @return the side with the specified name + * @throws IllegalArgumentException if the name does not correspond to any side + */ + public static Side fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the name of the side. + * + * @return the name of the side + */ + public String value() + { + return name(); + } + + /** + * Returns the opposite of this side, that is the other side. + * + * @return the opposite side + */ + public Side flip() + { + return Side.WHITE.equals(this) ? Side.BLACK : Side.WHITE; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Square.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Square.java new file mode 100644 index 0000000..1c4cb9b --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/Square.java @@ -0,0 +1,453 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess; + +import java.util.EnumMap; + +/** + * All possible squares on a board. + *

+ * Each value defines a single square, except for the special value + * {@link Square#NONE} which identifies that no square is selected or assigned. + */ +public enum Square +{ + /** + * The {@code A1} square. + */ + A1, + /** + * The {@code B1} square. + */ + B1, + /** + * The {@code C1} square. + */ + C1, + /** + * The {@code D1} square. + */ + D1, + /** + * The {@code E1} square. + */ + E1, + /** + * The {@code F1} square. + */ + F1, + /** + * The {@code G1} square. + */ + G1, + /** + * The {@code H1} square. + */ + H1, + /** + * The {@code A2} square. + */ + A2, + /** + * The {@code B2} square. + */ + B2, + /** + * The {@code C2} square. + */ + C2, + /** + * The {@code D2} square. + */ + D2, + /** + * The {@code E2} square. + */ + E2, + /** + * The {@code F2} square. + */ + F2, + /** + * The {@code G2} square. + */ + G2, + /** + * The {@code H2} square. + */ + H2, + /** + * The {@code A3} square. + */ + A3, + /** + * The {@code B3} square. + */ + B3, + /** + * The {@code C3} square. + */ + C3, + /** + * The {@code D3} square. + */ + D3, + /** + * The {@code E3} square. + */ + E3, + /** + * The {@code F3} square. + */ + F3, + /** + * The {@code G3} square. + */ + G3, + /** + * The {@code H3} square. + */ + H3, + /** + * The {@code A4} square. + */ + A4, + /** + * The {@code B4} square. + */ + B4, + /** + * The {@code C4} square. + */ + C4, + /** + * The {@code D4} square. + */ + D4, + /** + * The {@code E4} square. + */ + E4, + /** + * The {@code F4} square. + */ + F4, + /** + * The {@code G4} square. + */ + G4, + /** + * The {@code H4} square. + */ + H4, + /** + * The {@code A5} square. + */ + A5, + /** + * The {@code B5} square. + */ + B5, + /** + * The {@code C5} square. + */ + C5, + /** + * The {@code D5} square. + */ + D5, + /** + * The {@code E5} square. + */ + E5, + /** + * The {@code F5} square. + */ + F5, + /** + * The {@code G5} square. + */ + G5, + /** + * The {@code H5} square. + */ + H5, + /** + * The {@code A6} square. + */ + A6, + /** + * The {@code B6} square. + */ + B6, + /** + * The {@code C6} square. + */ + C6, + /** + * The {@code D6} square. + */ + D6, + /** + * The {@code E6} square. + */ + E6, + /** + * The {@code F6} square. + */ + F6, + /** + * The {@code G6} square. + */ + G6, + /** + * The {@code H6} square. + */ + H6, + /** + * The {@code A7} square. + */ + A7, + /** + * The {@code B7} square. + */ + B7, + /** + * The {@code C7} square. + */ + C7, + /** + * The {@code D7} square. + */ + D7, + /** + * The {@code E7} square. + */ + E7, + /** + * The {@code F7} square. + */ + F7, + /** + * The {@code G7} square. + */ + G7, + /** + * The {@code H7} square. + */ + H7, + /** + * The {@code A8} square. + */ + A8, + /** + * The {@code B8} square. + */ + B8, + /** + * The {@code C8} square. + */ + C8, + /** + * The {@code D8} square. + */ + D8, + /** + * The {@code E8} square. + */ + E8, + /** + * The {@code F8} square. + */ + F8, + /** + * The {@code G8} square. + */ + G8, + /** + * The {@code H8} square. + */ + H8, + /** + * Special value that represents no square in particular. + */ + NONE; + + private static final Square[] allSquares = Square.values(); + private static final Rank[] rankValues = Rank.values(); + private static final File[] fileValues = File.values(); + private static final long[] bitboard = new long[allSquares.length]; + + private static final EnumMap sideSquare = new EnumMap(Square.class); + + static + { + for (Square sq : allSquares) + { + bitboard[sq.ordinal()] = 1L << sq.ordinal(); + if (!Square.NONE.equals(sq)) + { + Square[] a = null; + if (File.FILE_A.equals(sq.getFile())) + { + a = new Square[1]; + a[0] = encode(sq.getRank(), File.FILE_B); + } + else if (File.FILE_H.equals(sq.getFile())) + { + a = new Square[1]; + a[0] = encode(sq.getRank(), File.FILE_G); + } + else + { + a = new Square[2]; + a[0] = encode(sq.getRank(), fileValues[sq.getFile().ordinal() - 1]); + a[1] = encode(sq.getRank(), fileValues[sq.getFile().ordinal() + 1]); + } + sideSquare.put(sq, a); + } + } + } + + /** + * Encodes a rank and a file into a square, returning the square value + * corresponding to the input values. + * + * @param rank a rank in the board + * @param file a file in the board + * @return the square that corresponds to the rank and file provided in input + */ + public static Square encode(Rank rank, File file) + { + return allSquares[rank.ordinal() * 8 + file.ordinal()]; + } + + /** + * Returns a square given its name. + *

+ * Same as invoking {@link Square#valueOf(String)}. + * + * @param v name of the square + * @return the square with the specified name + * @throws IllegalArgumentException if the name does not correspond to any + * square + */ + public static Square fromValue(String v) + { + return valueOf(v); + } + + /** + * Returns the square at position {@code index} in the board, or + * {@link Square#NONE} if the index is invalid. Valid indexes are included + * between 0 ({@link Square#A1}) and 63 ({@link Square#H8}), increasing with + * files and ranks respectively. Thus, index 1 corresponds to {@link Square#B1} + * and index 8 to {@link Square#A2}. + * + * @param index the index of the square + * @return the corresponding square, if index is valid, otherwise + * {@link Square#NONE} + */ + public static Square squareAt(int index) + { + if (index < 0 || index >= allSquares.length) + { + return Square.NONE; + } + return allSquares[index]; + } + + /** + * Returns the squares on the side of the given square. A square on the side is + * on the same rank and in adjacent files. For instance, side squares of + * {@link Square#D4} are the two adjacent squares on the 4th rank, + * {@link Square#C4} and {@link Square#E4}. + *

+ * Note that squares on the edge files ({@code A} and {@code H}) have only one + * side square instead of two (on files {@code B} and {@code G} respectively). + * + * @return the side squares of this square + */ + public Square[] getSideSquares() + { + return sideSquare.get(this); + } + + /** + * Returns the rank of the square. + * + * @return the rank of the square + */ + public Rank getRank() + { + return rankValues[this.ordinal() / 8]; + } + + /** + * Returns the file of the square. + * + * @return the file of the square + */ + public File getFile() + { + return fileValues[this.ordinal() % 8]; + } + + /** + * Returns the name of the square. + * + * @return the name of the square + */ + public String value() + { + return name(); + } + + /** + * Returns the bitboard representation of this square, that is, the single bit + * in a 64-bits bitmap at the same index of this square. If square is + * {@link Square#NONE}, an empty bitboard is returned. + * + * @return the bitboard representation of this square, as a long value + */ + public long getBitboard() + { + if (this == NONE) + { + return 0L; + } + return bitboard[this.ordinal()]; + } + + public static Square fromBitboard(long bitboard) + { + assert bitboard != 0; + assert Bitboard.hasOnly1Bit(bitboard); + + return Square.values()[Bitboard.bitScanForward(bitboard)]; + } + + /** + * Returns whether this is a light-square or not (i.e. a dark-square). + * + * @return {@code true} if the square is a light-square + */ + public boolean isLightSquare() + { + return (getBitboard() & Bitboard.lightSquares) != 0L; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/Move.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/Move.java new file mode 100644 index 0000000..a5366e5 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/Move.java @@ -0,0 +1,189 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.move; + +import org.shawn.games.Serendipity.Chess.Piece; +import org.shawn.games.Serendipity.Chess.Side; +import org.shawn.games.Serendipity.Chess.Square; +import org.apache.commons.lang3.StringUtils; + +/** + * The definition of a chess move, that is, a piece movement from its starting + * square (the origin square) to a destination square. Optionally, the move + * could specify a promotion piece used to replace a pawn in case of promotion. + */ +public class Move +{ + private final Square from; + private final Square to; + private final Piece promotion; + private int score; + + /** + * Creates a new move, using its origin and destination squares. + *

+ * Same as {@code new Move(from, to, Piece.NONE)}. + * + * @param from the origin square + * @param to the destination square + */ + public Move(Square from, Square to) + { + this(from, to, Piece.NONE); + } + + /** + * Creates a new move, defined by its origin square, its destination, and a + * promotion piece. + * + * @param from the origin square + * @param to the destination square + * @param promotion the promotion piece + */ + public Move(Square from, Square to, Piece promotion) + { + this.promotion = promotion; + this.from = from; + this.to = to; + this.score = 0; + } + + /** + * Creates a new move using a string representing the coordinates of the origin + * and destination squares, and possibly a promotion piece. The side is used to + * disambiguate the color of the promotion piece. + *

+ * Valid examples of strings that can be used to instantiate the move are + * {@code "e2e4"}, {@code "f1b5"} or {@code "a7a8Q"}. + * + * @param move the string representing the coordinates of the move + * @param side the side used to disambiguate the promotion piece + */ + public Move(String move, Side side) + { + this(Square.valueOf(move.substring(0, 2).toUpperCase()), Square.valueOf(move.substring(2, 4).toUpperCase()), + move.length() < 5 ? Piece.NONE + : Side.WHITE.equals(side) ? Piece.fromFenSymbol(move.substring(4, 5).toUpperCase()) + : Piece.fromFenSymbol(move.substring(4, 5).toLowerCase())); + } + + /** + * Returns the origin square. + * + * @return the origin square + */ + public Square getFrom() + { + return from; + } + + /** + * Returns the destination square. + * + * @return the destination square + */ + public Square getTo() + { + return to; + } + + /** + * Returns the promotion piece, if present. + * + * @return the promotion piece, or {@link Piece#NONE} if move is not a promotion + */ + public Piece getPromotion() + { + return promotion; + } + + /** + * Returns whether the move is a promotion. + * + * @return {@code true} if the move is a promotion + */ + public boolean isPromotion() + { + return !Piece.NONE.equals(getPromotion()); + } + + /** + * Checks if this move is equivalent to another, according to its definition. + * + * @param obj the other object reference to compare to this move + * @return {@code true} if this move and the object reference are equivalent + */ + @Override + public boolean equals(Object obj) + { + if (obj == null || !(obj instanceof Move)) + { + return false; + } + Move move = (Move) obj; + return move.getFrom().equals(getFrom()) && move.getTo().equals(getTo()) + && move.getPromotion().equals(getPromotion()); + + } + + /** + * Returns a hash code value for this move. + * + * @return a hash value for this move + */ + @Override + public int hashCode() + { + return toString().hashCode(); + } + + /** + * Returns a string representation of this move. + * + * @return a string representation of this move + */ + @Override + public String toString() + { + String promo = StringUtils.EMPTY; + if (!Piece.NONE.equals(promotion)) + { + promo = promotion.getFenSymbol(); + } + return from.toString().toLowerCase() + to.toString().toLowerCase() + promo.toLowerCase(); + } + + /** + * Returns the score of the move + * + * @return the score of the move + */ + public int getScore() + { + return score; + } + + /** + * Sets the score of the move + * + * @param the new score of the move + */ + public void setScore(int score) + { + this.score = score; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveConversionException.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveConversionException.java new file mode 100644 index 0000000..02f45dd --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveConversionException.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.move; + +/** + * Thrown to indicate a failure converting a move from a textual representation, + * most likely because of an invalid or unknown syntax. + */ +public class MoveConversionException extends RuntimeException +{ + private static final long serialVersionUID = 5523540383760826752L; + + /** + * Constructs a new move conversion exception. + */ + public MoveConversionException() + { + super(); + } + + /** + * Constructs a new move conversion exception with the specified detail message + * and cause. + * + * @param message the error message + * @param cause the cause + */ + public MoveConversionException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new move conversion exception with the specified detail message. + * + * @param message the error message + */ + public MoveConversionException(String message) + { + super(message); + } + + /** + * Constructs a new move conversion exception with the specified cause. + * + * @param cause the cause + */ + public MoveConversionException(Throwable cause) + { + super(cause); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveException.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveException.java new file mode 100644 index 0000000..fb0b032 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveException.java @@ -0,0 +1,67 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.move; + +/** + * Thrown to indicate a failure executing a move, for instance because the move + * is considered illegal in the context of the game it is played. + */ +public class MoveException extends RuntimeException +{ + + private static final long serialVersionUID = 6523240383760826752L; + + /** + * Constructs a new move exception. + */ + public MoveException() + { + super(); + } + + /** + * Constructs a new move exception with the specified detail message and cause. + * + * @param message the error message + * @param cause the cause + */ + public MoveException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new move exception with the specified detail message. + * + * @param message the error message + */ + public MoveException(String message) + { + super(message); + } + + /** + * Constructs a new move exception with the specified cause. + * + * @param cause the cause + */ + public MoveException(Throwable cause) + { + super(cause); + } + +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGenerator.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGenerator.java new file mode 100644 index 0000000..43d6db9 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGenerator.java @@ -0,0 +1,497 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.move; + +import org.shawn.games.Serendipity.Chess.*; + +import java.util.List; + +import static org.shawn.games.Serendipity.Chess.Bitboard.bitScanForward; +import static org.shawn.games.Serendipity.Chess.Bitboard.extractLsb; + +/** + * A handy collection of static utility methods for generating moves from a + * chess position. + */ +public class MoveGenerator +{ + + private MoveGenerator() + { + } + + /** + * Generates all pawn captures for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the captures are legal + * according to the standard rules of pawn movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the pawn captures + * @param moves a mutable list in which to append the generated pawn captures + */ + public static void generatePawnCaptures(Board board, List moves) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.PAWN)); + while (pieces != 0L) + { + int sourceIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(sourceIndex); + long attacks = Attacks.getPawnCaptures(side, sqSource.getBitboard(), board.getBitboard(), board.getEnPassantTarget()) + & ~board.getBitboard(side); + while (attacks != 0L) + { + int targetIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(targetIndex); + addPromotions(moves, side, sqTarget, sqSource); + } + } + } + + /** + * Generates all pawn moves, excluding captures, for the playing side in the + * given position, and appends them to the list passed as an argument. That + * implies the list must be mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of pawn movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the pawn moves + * @param moves a mutable list in which to append the generated pawn moves + */ + public static void generatePawnMoves(Board board, List moves) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.PAWN)); + while (pieces != 0L) + { + int sourceIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(sourceIndex); + long attacks = Attacks.getPawnMoves(side, sqSource.getBitboard(), board.getBitboard()); + while (attacks != 0L) + { + int targetIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(targetIndex); + addPromotions(moves, side, sqTarget, sqSource); + } + } + } + + private static void addPromotions(List moves, Side side, Square sqTarget, Square sqSource) + { + if (Side.WHITE.equals(side) && Rank.RANK_8.equals(sqTarget.getRank())) + { + moves.add(new Move(sqSource, sqTarget, Piece.WHITE_QUEEN)); + moves.add(new Move(sqSource, sqTarget, Piece.WHITE_ROOK)); + moves.add(new Move(sqSource, sqTarget, Piece.WHITE_BISHOP)); + moves.add(new Move(sqSource, sqTarget, Piece.WHITE_KNIGHT)); + } + + else if (Side.BLACK.equals(side) && Rank.RANK_1.equals(sqTarget.getRank())) + { + moves.add(new Move(sqSource, sqTarget, Piece.BLACK_QUEEN)); + moves.add(new Move(sqSource, sqTarget, Piece.BLACK_ROOK)); + moves.add(new Move(sqSource, sqTarget, Piece.BLACK_BISHOP)); + moves.add(new Move(sqSource, sqTarget, Piece.BLACK_KNIGHT)); + } + + else + { + moves.add(new Move(sqSource, sqTarget, Piece.NONE)); + } + } + + /** + * Generates all knight moves for the playing side in the given position, + * according to a bitboard mask used to specify the allowed target squares on + * the board. The generated moves are appended to the list passed as an + * argument, which must be mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of knight movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the knight moves + * @param moves a mutable list in which to append the generated knight moves + * @param mask bitboard mask of allowed targets + */ + public static void generateKnightMoves(Board board, List moves, long mask) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.KNIGHT)); + + while (pieces != 0L) + { + int knightIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(knightIndex); + long attacks = Attacks.getKnightAttacks(sqSource, mask); + + while (attacks != 0L) + { + int attackIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(attackIndex); + moves.add(new Move(sqSource, sqTarget, Piece.NONE)); + } + } + } + + /** + * Generates all knight moves for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of knight movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the knight moves + * @param moves a mutable list in which to append the generated knight moves + * @see MoveGenerator#generateKnightMoves(Board, List, long) + */ + public static void generateKnightMoves(Board board, List moves) + { + generateKnightMoves(board, moves, ~board.getBitboard(board.getSideToMove())); + } + + /** + * Generates all bishop moves for the playing side in the given position, + * according to a bitboard mask used to specify the allowed target squares on + * the board. The generated moves are appended to the list passed as an + * argument, which must be mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of bishop movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the bishop moves + * @param moves a mutable list in which to append the generated bishop moves + * @param mask bitboard mask of allowed targets + */ + public static void generateBishopMoves(Board board, List moves, long mask) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.BISHOP)); + while (pieces != 0L) + { + int sourceIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(sourceIndex); + long attacks = Attacks.getBishopAttacks(board.getBitboard(), sqSource) & mask; + while (attacks != 0L) + { + int attackIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(attackIndex); + moves.add(new Move(sqSource, sqTarget, Piece.NONE)); + } + } + } + + /** + * Generates all bishop moves for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of bishop movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the bishop moves + * @param moves a mutable list in which to append the generated bishop moves + * @see MoveGenerator#generateBishopMoves(Board, List, long) + */ + public static void generateBishopMoves(Board board, List moves) + { + generateBishopMoves(board, moves, ~board.getBitboard(board.getSideToMove())); + } + + /** + * Generates all rook moves for the playing side in the given position, + * according to a bitboard mask used to specify the allowed target squares on + * the board. The generated moves are appended to the list passed as an + * argument, which must be mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of rook movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the rook moves + * @param moves a mutable list in which to append the generated rook moves + * @param mask bitboard mask of allowed targets + */ + public static void generateRookMoves(Board board, List moves, long mask) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.ROOK)); + while (pieces != 0L) + { + int sourceIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(sourceIndex); + long attacks = Attacks.getRookAttacks(board.getBitboard(), sqSource) & mask; + while (attacks != 0L) + { + int attackIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(attackIndex); + moves.add(new Move(sqSource, sqTarget, Piece.NONE)); + } + } + } + + /** + * Generates all rook moves for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of rook movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the rook moves + * @param moves a mutable list in which to append the generated rook moves + * @see MoveGenerator#generateRookMoves(Board, List, long) + */ + public static void generateRookMoves(Board board, List moves) + { + generateRookMoves(board, moves, ~board.getBitboard(board.getSideToMove())); + } + + /** + * Generates all queen moves for the playing side in the given position, + * according to a bitboard mask used to specify the allowed target squares on + * the board. The generated moves are appended to the list passed as an + * argument, which must be mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of queen movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the queen moves + * @param moves a mutable list in which to append the generated queen moves + * @param mask bitboard mask of allowed targets + */ + public static void generateQueenMoves(Board board, List moves, long mask) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.QUEEN)); + + while (pieces != 0L) + { + int sourceIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(sourceIndex); + long attacks = Attacks.getQueenAttacks(board.getBitboard(), sqSource) & mask; + + while (attacks != 0L) + { + int attackIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(attackIndex); + moves.add(new Move(sqSource, sqTarget, Piece.NONE)); + } + } + } + + /** + * Generates all queen moves for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of queen movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the queen moves + * @param moves a mutable list in which to append the generated queen moves + * @see MoveGenerator#generateQueenMoves(Board, List, long) + */ + public static void generateQueenMoves(Board board, List moves) + { + generateQueenMoves(board, moves, ~board.getBitboard(board.getSideToMove())); + } + + /** + * Generates all king moves for the playing side in the given position, + * according to a bitboard mask used to specify the allowed target squares on + * the board. The generated moves are appended to the list passed as an + * argument, which must be mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of king movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the king moves + * @param moves a mutable list in which to append the generated king moves + * @param mask bitboard mask of allowed targets + */ + public static void generateKingMoves(Board board, List moves, long mask) + { + Side side = board.getSideToMove(); + long pieces = board.getBitboard(Piece.make(side, PieceType.KING)); + + while (pieces != 0L) + { + int sourceIndex = bitScanForward(pieces); + pieces = extractLsb(pieces); + Square sqSource = Square.squareAt(sourceIndex); + long attacks = Attacks.getKingAttacks(sqSource, mask); + + while (attacks != 0L) + { + int attackIndex = bitScanForward(attacks); + attacks = extractLsb(attacks); + Square sqTarget = Square.squareAt(attackIndex); + moves.add(new Move(sqSource, sqTarget, Piece.NONE)); + } + } + } + + /** + * Generates all king moves for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + *

+ * All moves have to be considered pseudo-legal: although the moves are legal + * according to the standard rules of rook movements, the resulting position + * might not be considered legal after they are played on the board. + * + * @param board the board from which to generate the king moves + * @param moves a mutable list in which to append the generated king moves + * @see MoveGenerator#generateKingMoves(Board, List, long) + */ + public static void generateKingMoves(Board board, List moves) + { + generateKingMoves(board, moves, ~board.getBitboard(board.getSideToMove())); + } + + /** + * Generates all castle moves for the playing side in the given position, and + * appends them to the list passed as an argument. That implies the list must be + * mutable in order for this method to work. + * + * @param board the board from which to generate the castle moves + * @param moves a mutable list in which to append the generated castle moves + */ + public static void generateCastleMoves(Board board, List moves) + { + Side side = board.getSideToMove(); + if (board.isKingAttacked()) + { + return; + } + if (board.getCastleRight(side).equals(CastleRight.KING_AND_QUEEN_SIDE) + || (board.getCastleRight(side).equals(CastleRight.KING_SIDE))) + { + if ((board.getBitboard() & board.getContext().getooAllSquaresBb(side)) == 0L) + { + if (!board.isSquareAttackedBy(board.getContext().getooSquares(side), side.flip())) + { + moves.add(board.getContext().getoo(side)); + } + } + } + if (board.getCastleRight(side).equals(CastleRight.KING_AND_QUEEN_SIDE) + || (board.getCastleRight(side).equals(CastleRight.QUEEN_SIDE))) + { + if ((board.getBitboard() & board.getContext().getoooAllSquaresBb(side)) == 0L) + { + if (!board.isSquareAttackedBy(board.getContext().getoooSquares(side), side.flip())) + { + moves.add(board.getContext().getooo(side)); + } + } + } + } + + /** + * Generates all possible pseudo-legal moves for the given position. + *

+ * A move is considered pseudo-legal when it is legal according to the standard + * rules of chess piece movements, but the resulting position might not be legal + * because of other rules (e.g. checks to the king). + * + * @param board the board from which to generate the pseudo-legal moves + * @param moves the list to write generated moves to + */ + public static void generatePseudoLegalMoves(Board board, List moves) + { + generatePawnCaptures(board, moves); + generatePawnMoves(board, moves); + generateKnightMoves(board, moves); + generateBishopMoves(board, moves); + generateRookMoves(board, moves); + generateQueenMoves(board, moves); + generateKingMoves(board, moves); + generateCastleMoves(board, moves); + } + + /** + * Generates all possible pseudo-legal captures for the given + * position. + *

+ * A move is considered a pseudo-legal capture when it takes an enemy piece and + * it is legal according to the standard rules of chess piece movements, but the + * resulting position might not be legal because of other rules (e.g. checks to + * the king). + * + * @param board the board from which to generate the pseudo-legal captures + * @param moves the list to write generated moves to + */ + public static void generatePseudoLegalCaptures(Board board, List moves) + { + Side other = board.getSideToMove().flip(); + generatePawnCaptures(board, moves); + generateKnightMoves(board, moves, board.getBitboard(other)); + generateBishopMoves(board, moves, board.getBitboard(other)); + generateRookMoves(board, moves, board.getBitboard(other)); + generateQueenMoves(board, moves, board.getBitboard(other)); + generateKingMoves(board, moves, board.getBitboard(other)); + } + + /** + * Generates all possible legal moves for the position according to + * the standard rules of chess. + * + * @param board the board from which to generate the legal moves + * @param moves the list to write generated moves to + * @throws MoveGeneratorException if it is not possible to generate the moves + */ + public static void generateLegalMoves(Board board, List moves) throws MoveGeneratorException + { + try + { + generatePseudoLegalMoves(board, moves); + moves.removeIf(move -> !board.isMoveLegal(move, false)); + } + catch (Exception e) + { + throw new MoveGeneratorException("Couldn't generate Legal moves: ", e); + } + } + +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGeneratorException.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGeneratorException.java new file mode 100644 index 0000000..a5d2265 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveGeneratorException.java @@ -0,0 +1,65 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.move; + +/** + * Thrown to indicate a failure generating a move. + */ +public class MoveGeneratorException extends RuntimeException +{ + private static final long serialVersionUID = 6523240383760826752L; + + /** + * Constructs a new move generator exception. + */ + public MoveGeneratorException() + { + super(); + } + + /** + * Constructs a new move generator exception with the specified detail message + * and cause. + * + * @param message the error message + * @param cause the cause + */ + public MoveGeneratorException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new move generator exception with the specified detail message. + * + * @param message the error message + */ + public MoveGeneratorException(String message) + { + super(message); + } + + /** + * Constructs a new move generator exception with the specified cause. + * + * @param cause the cause + */ + public MoveGeneratorException(Throwable cause) + { + super(cause); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveList.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveList.java new file mode 100644 index 0000000..e520552 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/move/MoveList.java @@ -0,0 +1,1017 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.move; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Function; + +import org.shawn.games.Serendipity.Chess.Bitboard; +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.Constants; +import org.shawn.games.Serendipity.Chess.File; +import org.shawn.games.Serendipity.Chess.Piece; +import org.shawn.games.Serendipity.Chess.PieceType; +import org.shawn.games.Serendipity.Chess.Rank; +import org.shawn.games.Serendipity.Chess.Side; +import org.shawn.games.Serendipity.Chess.Square; +import org.shawn.games.Serendipity.Chess.util.StringUtil; +import org.apache.commons.lang3.StringUtils; + +/** + * A convenient data structure to store an ordered sequence of moves and access + * to their human-readable representation in one of the standard chess formats. + * This implementation can be used to hold the list of moves played in a chess + * game. + *

+ * The move list keeps a reference to a base initial position (by default, the + * standard starting chess position) used to validate and disambiguate between + * moves. + *

+ * This data structure is a {@link List}, thus the standard API of the Java + * collection is available for this class as well. + */ +public class MoveList extends LinkedList implements List +{ + private static final long serialVersionUID = -6204280556340150806L; + private static final ThreadLocal boardHolder = ThreadLocal.withInitial(Board::new); + private static final Move nullMove = new Move(Square.NONE, Square.NONE); + + private final String startFEN; + private boolean dirty = true; + + private String[] sanArray; + private String[] fanArray; + private int parent; + private int index; + + /** + * Constructs an empty move list, using the standard starting position as a + * base. + */ + public MoveList() + { + this(Constants.startStandardFENPosition); + } + + /** + * Constructs an empty move list, using the provided initial position as a base, + * retrieved in Forsyth-Edwards Notation (FEN). + * + * @param initialFEN the FEN representation of the base position + */ + public MoveList(String initialFEN) + { + this.startFEN = initialFEN; + } + + /** + * Constructs a new move list starting from an existing one. The new instance + * will use the initial position of the existing list as a base. + * + * @param halfMoves the existing move list + */ + public MoveList(MoveList halfMoves) + { + this(halfMoves.getStartFen()); + super.addAll(halfMoves); + } + + /** + * Returns a reference to the board representing the last position after the + * moves are played. + * + * @return the board representing the position after the moves are played + */ + private static Board getBoard() + { + return boardHolder.get(); + } + + /** + * Encodes the move to its Short Algebraic Notation (SAN), using the context of + * the given board. + * + * @param board the board used as context for encoding the move + * @param move the move to encode + * @return the SAN notation of the move + * @throws MoveConversionException if the move conversion fails + */ + // encode the move to SAN move and update thread local board + private static String encodeToSan(final Board board, Move move) throws MoveConversionException + { + return encode(board, move, Piece::getSanSymbol); + } + + /** + * Encodes the move to its Figurine Algebraic Notation (FAN), using the context + * of the given board. + * + * @param board the board used as context for encoding the move + * @param move the move to encode + * @return the FAN notation of the move + * @throws MoveConversionException if the move conversion fails + */ + // encode the move to FAN move and update thread local board + private static String encodeToFan(final Board board, Move move) throws MoveConversionException + { + return encode(board, move, Piece::getFanSymbol); + } + + /** + * Encodes the move using a conversion function and the given board as context. + * + * @param board the board used as context for encoding the move + * @param move the move to encode + * @param notation the conversion function to transform the move to its string + * representation + * @return the notation of the move + * @throws MoveConversionException if the move conversion fails + */ + // encode the move to SAN/FAN move and update thread local board + private static String encode(final Board board, Move move, Function notation) + throws MoveConversionException + { + StringBuilder san = new StringBuilder(); + Piece piece = board.getPiece(move.getFrom()); + if (piece.getPieceType().equals(PieceType.KING)) + { + int delta = move.getTo().getFile().ordinal() - move.getFrom().getFile().ordinal(); + if (Math.abs(delta) >= 2) + { // is castle + board.doMove(move); + san.append(delta > 0 ? "O-O" : "O-O-O"); + addCheckFlag(board, san); + return san.toString(); + } + } + boolean pawnMove = piece.getPieceType().equals(PieceType.PAWN) + && move.getFrom().getFile().equals(move.getTo().getFile()); + boolean ambResolved = false; + san.append(notation.apply(piece)); + if (!pawnMove) + { + // resolving ambiguous move + long amb = board.squareAttackedByPieceType(move.getTo(), board.getSideToMove(), piece.getPieceType()); + amb &= ~move.getFrom().getBitboard(); + if (amb != 0L) + { + List fromList = Bitboard.bbToSquareList(amb); + for (Square from : fromList) + { + if (!board.isMoveLegal(new Move(from, move.getTo()), false)) + { + amb ^= from.getBitboard(); + } + } + } + if (amb != 0L) + { + if ((Bitboard.getFilebb(move.getFrom()) & amb) == 0L) + { + san.append(move.getFrom().getFile().getNotation().toLowerCase()); + } + else if ((Bitboard.getRankbb(move.getFrom()) & amb) == 0L) + { + san.append(move.getFrom().getRank().getNotation().toLowerCase()); + } + else + { + san.append(move.getFrom().toString().toLowerCase()); + } + ambResolved = true; + } + } + + board.doMove(move); + + Piece captured = board.getBackup().getLast().getCapturedPiece(); + boolean isCapture = !captured.equals(Piece.NONE); + if (isCapture) + { + if (!ambResolved && piece.getPieceType().equals(PieceType.PAWN)) + { + san.append(move.getFrom().getFile().getNotation().toLowerCase()); + } + san.append("x"); + } + san.append(move.getTo().toString().toLowerCase()); + if (!move.getPromotion().equals(Piece.NONE)) + { + san.append("="); + san.append(notation.apply(move.getPromotion())); + } + addCheckFlag(board, san); + return san.toString(); + } + + private static void addCheckFlag(Board board, StringBuilder san) + { + + if (board.isKingAttacked()) + { + if (board.isMated()) + { + san.append("#"); + } + else + { + san.append("+"); + } + } + } + + private static long findLegalSquares(Board board, Square to, Piece promotion, long pieces) + { + long result = 0L; + + if (pieces != 0L) + { + for (Square sqSource : Bitboard.bbToSquareList(pieces)) + { + Move move = new Move(sqSource, to, promotion); + if (board.isMoveLegal(move, true)) + { + result |= sqSource.getBitboard(); + break; + } + } + } + + return result; + } + + /** + * Creates a new instance using an existing list of moves. The new instance will + * use the initial position of the existing list as a base. + *

+ * The returned list will contain only the first {@code finalIndex} moves of the + * original list, or all the elements if {@code finalIndex} is outside the + * boundaries of the source list. + * + * @param startMoves the existing list of moves + * @param finalIndex the last index of the source list to use + * @return the new list of moves + * @throws MoveConversionException if the starting list of moves is invalid + */ + public static MoveList createMoveListFrom(MoveList startMoves, int finalIndex) throws MoveConversionException + { + String fen = null; + final Board b = getBoard(); + if (!b.getFen().equals(startMoves.getStartFen())) + { + b.loadFromFen(startMoves.getStartFen()); + } + int i = 0; + for (Move move : startMoves) + { + i++; + + b.doMove(move); + + if (i >= finalIndex) + { + fen = b.getFen(); + break; + } + } + if (fen == null) + { + fen = b.getFen(); + } + return new MoveList(fen); + } + + /** + * Returns the index of the moves list. + * + * @return the index of the list + */ + public int getIndex() + { + return index; + } + + /** + * Sets the index of the moves list. + * + * @param index the index of the list + */ + public void setIndex(int index) + { + this.index = index; + } + + @Override + public void add(int index, Move move) + { + dirty = true; + super.add(index, move); + } + + @Override + public boolean add(Move move) + { + dirty = true; + return super.add(move); + } + + @Override + public boolean addAll(Collection moves) + { + dirty = true; + return super.addAll(moves); + } + + @Override + public boolean addAll(int index, Collection moves) + { + dirty = true; + return super.addAll(index, moves); + } + + @Override + public Move removeFirst() + { + dirty = true; + return super.removeFirst(); + } + + @Override + public Move removeLast() + { + dirty = true; + return super.removeLast(); + } + + @Override + public boolean remove(Object o) + { + dirty = true; + return super.remove(o); + } + + @Override + public Move remove(int index) + { + dirty = true; + return super.remove(index); + } + + @Override + public void clear() + { + dirty = true; + sanArray = null; + fanArray = null; + super.clear(); + } + + /** + * Converts the list of moves into a Short Algebraic Notation (SAN) + * representation that does not include move numbers, for example + * {@code "e4 e5 Nf3 Bc5"}. + * + * @return the SAN representation of the list of moves without move numbers + * @throws MoveConversionException in case a conversion error occurs during the + * process + * @see MoveList#toSanWithMoveNumbers() + */ + public String toSan() throws MoveConversionException + { + return toStringWithoutMoveNumbers(toSanArray()); + } + + /** + * Converts the list of moves into a Short Algebraic Notation (SAN) + * representation that does include move numbers, for example + * {@code "1. e4 e5 2. Nf3 Bc5"}. + * + * @return the SAN representation of the list of moves with move numbers + * @throws MoveConversionException in case a conversion error occurs during the + * process + * @see MoveList#toSan() + */ + public String toSanWithMoveNumbers() throws MoveConversionException + { + return toStringWithMoveNumbers(toSanArray()); + } + + /** + * Converts the list of moves into a Figurine Algebraic Notation (FAN) + * representation that does not include move numbers, for example + * {@code "♙e4 ♟e5 ♘f3 ♝c5"}. + * + * @return the FAN representation of the list of moves without move numbers + * @throws MoveConversionException in case a conversion error occurs during the + * process + * @see MoveList#toFanWithMoveNumbers() + */ + public String toFan() throws MoveConversionException + { + return toStringWithoutMoveNumbers(toFanArray()); + } + + /** + * Converts the list of moves into a Figurine Algebraic Notation (FAN) + * representation that does include move numbers, for example + * {@code "1. ♙e4 ♟e5 2. ♘f3 ♝c5"}. + * + * @return the FAN representation of the list of moves with move numbers + * @throws MoveConversionException in case a conversion error occurs during the + * process + * @see MoveList#toFan() + */ + public String toFanWithMoveNumbers() throws MoveConversionException + { + return toStringWithMoveNumbers(toFanArray()); + } + + private String toStringWithoutMoveNumbers(String[] moveArray) throws MoveConversionException + { + StringBuilder sb = new StringBuilder(); + for (String move : moveArray) + { + sb.append(move); + sb.append(StringUtils.SPACE); + } + return sb.toString(); + } + + private String toStringWithMoveNumbers(String[] moveArray) throws MoveConversionException + { + StringBuilder sb = new StringBuilder(); + for (int halfMove = 0; halfMove < moveArray.length; halfMove++) + { + if (halfMove % 2 == 0) + { + sb.append((halfMove / 2) + 1).append(". "); + } + sb.append(moveArray[halfMove]).append(StringUtils.SPACE); + } + return sb.toString(); + } + + /** + * Returns an array of strings representing the moves in Short Algebraic + * Notation (SAN). + * + * @return the SAN representations of the list of moves + * @throws MoveConversionException in case a conversion error occurs during the + * process + */ + public String[] toSanArray() throws MoveConversionException + { + if (!dirty && sanArray != null) + { + return sanArray; + } + updateSanArray(); + updateFanArray(); + return sanArray; + } + + /** + * Returns an array of strings representing the moves in Figurine Algebraic + * Notation (FAN). + * + * @return the FAN representations of the list of moves + * @throws MoveConversionException in case a conversion error occurs during the + * process + */ + public String[] toFanArray() throws MoveConversionException + { + if (!dirty && fanArray != null) + { + return fanArray; + } + updateSanArray(); + updateFanArray(); + return fanArray; + } + + private void updateSanArray() throws MoveConversionException + { + sanArray = new String[this.size()]; + final Board b = getBoard(); + if (!b.getFen().equals(getStartFen())) + { + b.loadFromFen(getStartFen()); + } + int i = 0; + for (Move move : this) + { + sanArray[i++] = encodeToSan(b, move); + } + dirty = false; + } + + private void updateFanArray() throws MoveConversionException + { + fanArray = new String[this.size()]; + final Board b = getBoard(); + if (!b.getFen().equals(getStartFen())) + { + b.loadFromFen(getStartFen()); + } + int i = 0; + for (Move move : this) + { + fanArray[i++] = encodeToFan(b, move); + } + dirty = false; + } + + /** + * Returns the Forsyth–Edwards Notation (FEN) string that defines the initial + * position of the list of moves. + * + * @return the FEN representation of the initial position + */ + public String getStartFen() + { + return startFEN; + } + + /** + * Reloads the list with a sequence of moves separated by spaces and provided in + * input in their algebraic form (e.g. {@code "e2e4"} or {@code "g8f6"}). The + * base initial position will be left untouched. + * + * @param text the string representing the algebraic list of moves + * @throws MoveConversionException if it is not possible to parse and convert + * the moves + */ + public synchronized void loadFromText(String text) throws MoveConversionException + { + final Board b = getBoard(); + if (!b.getFen().equals(getStartFen())) + { + b.loadFromFen(getStartFen()); + } + try + { + Side side = b.getSideToMove(); + text = StringUtil.normalize(text); + String[] m = text.split(StringUtils.SPACE); + int i = 0; + for (String strMove : m) + { + Move move = new Move(strMove, side); + add(i++, move); + side = side.flip(); + } + } + catch (Exception e) + { + throw new MoveConversionException("Couldn't parse text to MoveList: " + e.getMessage()); + } + + } + + /** + * Adds a move defined by its Short Algebraic Notation (SAN) to the list. + *

+ * Same as invoking {@code addSanMove(san, false, true)}. + * + * @param san the SAN representation of the move to be added + * @throws MoveConversionException if it is not possible to parse or validate + * the move + * @see MoveList#addSanMove(String, boolean, boolean) + */ + public void addSanMove(String san) throws MoveConversionException + { + addSanMove(san, false, true); + } + + /** + * Adds a move defined by its Short Algebraic Notation (SAN) to the list. It is + * possible to control whether to replay the moves already present in the list, + * as well as if to perform a full validation or not. When a full validation is + * requested, additional checks are performed to assess the validity of the + * move, such as if the side to move is consistent with the position, if castle + * moves or promotions are allowed, etc. + * + * @param san the SAN representation of the move to be added + * @param replay if {@code true}, existing moves will be played again + * @param fullValidation if {@code true}, a full validation of the position will + * be performed + * @throws MoveConversionException if it is not possible to parse or validate + * the move + */ + public void addSanMove(String san, boolean replay, boolean fullValidation) throws MoveConversionException + { + final Board b = getBoard(); + + if (replay) + { + if (!b.getFen().equals(getStartFen())) + { + b.loadFromFen(getStartFen()); + } + + for (Move move : this) + { + b.doMove(move); + } + } + + Move move = decodeSan(b, san, b.getSideToMove()); + + if (move == nullMove) + { + return; + } + + b.doMove(move); + + add(this.size(), move); + } + + /** + * Reloads the list with a sequence of moves provided in input in their Short + * Algebraic Notation (SAN) (e.g. {@code "1. e4 e5 2. Nf3 Bc5"}). The base + * initial position will be left untouched. + * + * @param text the SAN representation of the list of moves + * @throws MoveConversionException if it is not possible to parse and convert + * the moves + */ + public void loadFromSan(String text) throws MoveConversionException + { + final Board b = getBoard(); + if (!b.getFen().equals(getStartFen())) + { + b.loadFromFen(getStartFen()); + } + try + { + text = StringUtil.normalize(text); + String[] m = text.split(StringUtils.SPACE); + for (String strMove : m) + { + if (strMove.startsWith("$")) + { + continue; + } + if (strMove.contains("...")) + { + continue; + } + if (strMove.contains(".")) + { + strMove = StringUtil.afterSequence(strMove, "."); + } + if (StringUtils.isBlank(strMove)) + { + continue; + } + addSanMove(strMove); + } + } + catch (MoveConversionException e1) + { + throw e1; + } + catch (Exception e2) + { + throw new MoveConversionException("Couldn't parse SAN to MoveList: " + e2.getMessage()); + } + } + + /** + * Converts a move defined by its Short Algebraic Notation (SAN) to an instance + * of {@link Move}, using the given board and side as context. + * + * @param board the board in which the move is played + * @param san the SAN representation of the move + * @param side the side executing the move + * @return the converted move + * @throws MoveConversionException if it is not possible to convert the move + */ + // decode SAN to move + protected Move decodeSan(Board board, String san, Side side) throws MoveConversionException + { + + if (san.equalsIgnoreCase("Z0")) + { + return nullMove; + } + san = normalizeSan(san); + + String strPromotion = StringUtil.afterSequence(san, "=", 1); + san = StringUtil.beforeSequence(san, "="); + + char lastChar = san.charAt(san.length() - 1); + // FIX missing equal sign for pawn promotions + if (Character.isLetter(lastChar) && Character.toUpperCase(lastChar) != 'O') + { + san = san.substring(0, san.length() - 1); + strPromotion = String.valueOf(lastChar); + } + + if (san.equals("O-O") || san.equals("O-O-O")) + { // is castle + if (san.equals("O-O")) + { + return board.getContext().getoo(side); + } + else + { + return board.getContext().getooo(side); + } + } + + if (san.length() == 3 && Character.isUpperCase(san.charAt(2))) + { + strPromotion = san.substring(2, 3); + san = san.substring(0, 2); + } + + Square from = Square.NONE; + Square to; + try + { + to = Square.valueOf(StringUtil.lastSequence(san.toUpperCase(), 2)); + } + catch (Exception e) + { + throw new MoveConversionException("Couldn't parse destination square[" + san + "]: " + san.toUpperCase()); + } + Piece promotion = StringUtils.isEmpty(strPromotion) ? Piece.NONE + : Piece.fromFenSymbol( + side.equals(Side.WHITE) ? strPromotion.toUpperCase() : strPromotion.toLowerCase()); + + if (san.length() == 2) + { // is pawn move + long mask = Bitboard.getBbtable(to) - 1L; + long xfrom = (side.equals(Side.WHITE) ? mask : ~mask) & Bitboard.getFilebb(to) + & board.getBitboard(Piece.make(side, PieceType.PAWN)); + int f = side.equals(Side.BLACK) ? Bitboard.bitScanForward(xfrom) : Bitboard.bitScanReverse(xfrom); + if (f >= 0 && f <= 63) + { + from = Square.squareAt(f); + } + } + else + { + String strFrom = (san.contains("x") ? StringUtil.beforeSequence(san, "x") + : san.substring(0, san.length() - 2)); + + if (strFrom == null || strFrom.length() == 0 || strFrom.length() > 3) + { + throw new MoveConversionException("Couldn't parse 'from' square " + san + ": Too many/few characters."); + } + + PieceType fromPiece = PieceType.PAWN; + + if (Character.isUpperCase(strFrom.charAt(0))) + { + fromPiece = PieceType.fromSanSymbol(String.valueOf(strFrom.charAt(0))); + } + + if (strFrom.length() == 3) + { + from = Square.valueOf(strFrom.substring(1, 3).toUpperCase()); + } + else + { + String location = StringUtils.EMPTY; + if (strFrom.length() == 2) + { + if (Character.isUpperCase(strFrom.charAt(0))) + { + location = strFrom.substring(1, 2); + } + else + { + location = strFrom.substring(0, 2); + from = Square.valueOf(location.toUpperCase()); + } + } + else + { + if (Character.isLowerCase(strFrom.charAt(0))) + { + location = strFrom; + } + } + if (location.length() < 2) + { + // resolving ambiguous from + long xfrom = board.squareAttackedByPieceType(to, board.getSideToMove(), fromPiece); + if (location.length() > 0) + { + if (Character.isDigit(location.charAt(0))) + { + int irank = Integer.parseInt(location); + if (!(irank >= 1 && irank <= 8)) + { + throw new MoveConversionException("Couldn't parse rank: " + location); + } + Rank rank = Rank.allRanks[irank - 1]; + xfrom &= Bitboard.getRankbb(rank); + } + else + { + try + { + File file = File.valueOf("FILE_" + location.toUpperCase()); + xfrom &= Bitboard.getFilebb(file); + } + catch (Exception e) + { + throw new MoveConversionException("Couldn't parse file: " + location); + } + } + } + if (xfrom != 0L) + { + if (!Bitboard.hasOnly1Bit(xfrom)) + { + xfrom = findLegalSquares(board, to, promotion, xfrom); + } + int f = Bitboard.bitScanForward(xfrom); + if (f >= 0 && f <= 63) + { + from = Square.squareAt(f); + } + } + } + } + + } + if (from.equals(Square.NONE)) + { + throw new MoveConversionException("Couldn't parse 'from' square " + san + " to setup: " + board.getFen()); + } + return new Move(from, to, promotion); + } + + /** + * Returns the Forsyth-Edwards Notation (FEN) representation of the position + * after the moves of this list, until index {@code atMoveIndex} (excluded), are + * executed from the base initial position. + *

+ * Same as invoking {@code getFen(atMoveIndex, true)}. + * + * @param atMoveIndex the index until which to execute the moves + * @return the FEN string notation of the position after the wanted number of + * moves are played from the initial position + * @see MoveList#getFen(int, boolean) + */ + public String getFen(int atMoveIndex) + { + return getFen(atMoveIndex, true); + } + + /** + * Returns the Forsyth-Edwards Notation (FEN) representation of the position + * after the moves of this list, until index {@code atMoveIndex} (excluded), are + * executed from the base initial position. Full and half moves counters are + * included in the output if the relative flag is enabled. + * + * @param atMoveIndex the index until which to execute the moves + * @param includeCounters if {@code true}, move counters are included in the + * resulting string + * @return the FEN string notation of the position after the wanted number of + * moves are played from the initial position + */ + public String getFen(int atMoveIndex, boolean includeCounters) + { + final Board b = getBoard(); + if (!b.getFen().equals(getStartFen())) + { + b.loadFromFen(getStartFen()); + } + int i = 0; + for (Move move : this) + { + i++; + b.doMove(move); + + if (i >= atMoveIndex) + { + return b.getFen(includeCounters); + } + } + return null; + } + + /** + * Returns the Forsyth-Edwards Notation (FEN) representation of the position + * after all the moves of this list are executed starting from the base initial + * position. + *

+ * Same as invoking {@code getFen(this.size(), true)}. + * + * @return the FEN string notation of the position after the moves are played + * from the initial position + * @see MoveList#getFen(int, boolean) + */ + public String getFen() + { + return getFen(this.size()); + } + + /** + * Returns the parent index of the list of moves. + * + * @return the parent index + */ + public int getParent() + { + return parent; + } + + /** + * Sets the parent index of the list of moves. + * + * @param parent the parent index to set + */ + public void setParent(int parent) + { + this.parent = parent; + } + + /** + * Returns a string representation of the list. + * + * @return a string representation of the list of moves + */ + @Override + public String toString() + { + StringBuilder b = new StringBuilder(); + for (Move move : this) + { + b.append(move.toString()); + b.append(StringUtils.SPACE); + } + return b.toString().trim(); + } + + /** + * Returns a hash code value for this move list. + * + * @return a hash value for this move list + */ + @Override + public int hashCode() + { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + toString().hashCode(); + return result; + } + + /** + * Checks if this list is equivalent to another, that is, if the lists contains + * the same moves in the same order. + * + * @param obj the other object reference to compare to this list of moves + * @return {@code true} if this list and the object reference are equivalent + */ + @Override + public boolean equals(Object obj) + { + if (obj instanceof MoveList) + { + MoveList l = (MoveList) obj; + if (l.size() != this.size()) + { + return false; + } + for (int i = 0; i < l.size(); i++) + { + if (!l.get(i).equals(this.get(i))) + { + return false; + } + } + return true; + } + return false; + } + + private String normalizeSan(String san) + { // TODO regex? + return san.replace("+", StringUtils.EMPTY).replace("#", StringUtils.EMPTY).replace("!", StringUtils.EMPTY) + .replace("?", StringUtils.EMPTY).replace("ep", StringUtils.EMPTY).replace("\n", StringUtils.SPACE); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/StringUtil.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/StringUtil.java new file mode 100644 index 0000000..444ffda --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/StringUtil.java @@ -0,0 +1,201 @@ +/* + * Copyright 2017 Ben-Hur Carlos Vieira Langoni Junior + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.shawn.games.Serendipity.Chess.util; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; + +/** + * A utility collection of operations on strings. + * + * @author bhlangonijr + */ +public class StringUtil +{ + /** + * Extracts the last char sequence from a string, that is, the last {@code size} + * chars. + * + * @param str the string + * @param size the number of chars to extract + * @return the extracted substring + */ + public static String lastSequence(final String str, int size) + { + return str.substring(str.length() - size); + } + + /** + * Extracts from a string the char sequence of length {@code size} that occurs + * after the given subsequence. + * + * @param str the string + * @param seq the subsequence to search + * @param size the number of chars to extract + * @return the extracted substring, or an empty string if the subsequence is not + * found + */ + public static String afterSequence(final String str, final String seq, int size) + { + int idx = str.indexOf(seq) + seq.length(); + if (idx == 0) + { + return StringUtils.EMPTY; + } + return str.substring(idx, idx + size); + } + + /** + * Extracts from a string the char sequence that occurs after the given + * subsequence. + * + * @param str the string + * @param seq the subsequence to search + * @return the extracted substring, or an empty string if the subsequence is not + * found + */ + public static String afterSequence(final String str, final String seq) + { + int idx = str.indexOf(seq) + seq.length(); + if (idx == 0) + { + return StringUtils.EMPTY; + } + return str.substring(idx); + } + + /** + * Extracts from a string the char sequence that occurs before the given + * subsequence. + * + * @param str the string + * @param seq the subsequence to search + * @return the extracted substring, or the original string if the subsequence is + * not found + */ + public static String beforeSequence(final String str, final String seq) + { + int idx = str.indexOf(seq); + if (idx == -1) + { + return str; + } + return str.substring(0, idx); + } + + /** + * Removes extra whitespaces in the string. It replaces each sequence of two or + * more whitespaces with a single one. + * + * @param str the string from which to remove extra whitespaces + * @return the string without extra whitespaces + */ + public static String normalize(String str) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < str.length(); i++) + { + if (i < str.length() - 1 && str.charAt(i) == ' ' && str.charAt(i + 1) == ' ') + { + continue; + } + sb.append(str.charAt(i)); + } + return sb.toString(); + } + + /** + * Replaces inside a string builder every occurrence of a subsequence of chars + * with another one. It returns the modified builder. + * + * @param builder the builder in which to replace the subsequence of chars + * @param from the subsequence to replace with another one + * @param to the subsequence with which to replace the original one + * @return the modified string builder + */ + public static StringBuilder replaceAll(StringBuilder builder, String from, String to) + { + int index = builder.indexOf(from); + while (index != -1) + { + builder.replace(index, index + from.length(), to); + index += to.length(); + index = builder.indexOf(from, index); + } + return builder; + } + + /** + * Replaces the chars in a builder with the ones stored in the translation + * table. The indexes in the table refers to the code points of the chars to be + * replaced. + * + * @param str the string builder in which to replace the chars + * @param table the translation table + */ + public static void translate(StringBuilder str, char[] table) + { + for (int idx = 0; idx < str.length(); ++idx) + { + char ch = str.charAt(idx); + if (ch < table.length) + { + ch = table[ch]; + str.setCharAt(idx, ch); + } + } + } + + /** + * Replaces the chars in a builder with the ones stored in the translation map. + * + * @param str the string builder in which to replace the chars + * @param map the translation map + */ + public static void translate(StringBuilder str, Map map) + { + for (int idx = 0; idx < str.length(); ++idx) + { + char ch = str.charAt(idx); + Character conversion = map.get(ch); + if (conversion != null) + str.setCharAt(idx, conversion); + } + } + + /** + * Counts the occurrences of a char inside a string. + * + * @param str the string in which to count the occurrences of the char + * @param charToCount the char to count + * @return the number of times the char is found inside the string + */ + public static int countOccurrences(String str, char charToCount) + { + int count = 0; + for (int i = 0; i < str.length(); i++) + { + if (str.charAt(i) == charToCount) + { + count++; + } + } + return count; + } + +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/XorShiftRandom.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/XorShiftRandom.java new file mode 100644 index 0000000..bb861fe --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Chess/util/XorShiftRandom.java @@ -0,0 +1,56 @@ +package org.shawn.games.Serendipity.Chess.util; + +/** + * A utility class that is used to generate pseudorandom numbers bases on XOR + * and bit shifts operations. + * Xorshift random + * generators are simple and efficient software implementations of number + * generators. + */ +public class XorShiftRandom +{ + private long seed; + + /** + * Constructs a new random number generator using a custom long seed. + * + * @param seed the initial seed + */ + public XorShiftRandom(long seed) + { + this.seed = seed; + } + + /** + * Constructs a new random number generator. + */ + public XorShiftRandom() + { + this(System.nanoTime()); + } + + /** + * Returns the next pseudorandom long value from this random number generator's + * sequence. + * + * @return the next pseudorandom long value + */ + public long nextLong() + { + seed ^= seed >>> 12; + seed ^= seed << 25; + seed ^= seed >>> 27; + return seed * 0x2545F4914F6CDD1DL; + } + + /** + * Returns the next sparse pseudorandom long value from this random number + * generator's sequence. + * + * @return the next sparse pseudorandom long value + */ + public long nextSparseLong() + { + return nextLong() & nextLong() & nextLong(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorCache.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorCache.java new file mode 100644 index 0000000..a3f4384 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorCache.java @@ -0,0 +1,79 @@ +package org.shawn.games.Serendipity.NNUE; + +import java.util.Arrays; + +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.PieceType; +import org.shawn.games.Serendipity.Chess.Side; + +public class AccumulatorCache +{ + public class Entry + { + public final short[] storedAccumulator; + private final long[] bySide; + private final long[] byPieceType; + + public Entry() + { + storedAccumulator = new short[NNUE.HIDDEN_SIZE]; + bySide = new long[Side.values().length]; + byPieceType = new long[PieceType.validValues().length]; + } + + public long getBitboard(Side side, PieceType pieceType) + { + return bySide[side.ordinal()] & byPieceType[pieceType.ordinal()]; + } + + public void update(Board board) + { + for (Side side : Side.values()) + { + bySide[side.ordinal()] = board.getBitboard(side); + } + + for (PieceType pieceType : PieceType.validValues()) + { + byPieceType[pieceType.ordinal()] = board.getBitboard(pieceType); + } + } + } + + final private Entry[][] entries; + + public AccumulatorCache(NNUE network) + { + entries = new Entry[Side.values().length][NNUE.INPUT_BUCKET_SIZE]; + + for (int i = 0; i < entries.length; i++) + { + for (int j = 0; j < entries[0].length; j++) + { + entries[i][j] = new Entry(); + } + } + + clear(network); + } + + public void clear(NNUE network) + { + for (Entry[] row : entries) + { + for (Entry entry : row) + { + assert entry.storedAccumulator.length == NNUE.HIDDEN_SIZE; + + System.arraycopy(network.L1Biases, 0, entry.storedAccumulator, 0, NNUE.HIDDEN_SIZE); + Arrays.fill(entry.bySide, 0L); + Arrays.fill(entry.byPieceType, 0L); + } + } + } + + public Entry get(Side side, int kingBucket) + { + return entries[side.ordinal()][kingBucket]; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorStack.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorStack.java new file mode 100644 index 0000000..94f306c --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/AccumulatorStack.java @@ -0,0 +1,310 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.NNUE; + +import org.shawn.games.Serendipity.Search.AlphaBeta; + +import org.shawn.games.Serendipity.Chess.AccumulatorDiff; +import org.shawn.games.Serendipity.Chess.Bitboard; +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.Piece; +import org.shawn.games.Serendipity.Chess.PieceType; +import org.shawn.games.Serendipity.Chess.Side; +import org.shawn.games.Serendipity.Chess.Square; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class AccumulatorStack +{ + public class Accumulator + { + short[] values; + Side color; + AccumulatorDiff diff; + int kingBucket; + boolean needsRefresh; + + public Accumulator() + { + this.values = new short[NNUE.HIDDEN_SIZE]; + } + + public Accumulator(NNUE network, Side color) + { + this.values = network.L1Biases.clone(); + this.color = color; + this.needsRefresh = false; + } + + private void addSub(Accumulator prev, int featureIndexToAdd, int featureIndexToSubtract) + { + featureIndexToAdd = featureIndexToAdd + kingBucket * NNUE.FEATURE_SIZE; + featureIndexToSubtract = featureIndexToSubtract + kingBucket * NNUE.FEATURE_SIZE; + + INFERENCE.addSub(values, prev.values, network.L1Weights[featureIndexToAdd], + network.L1Weights[featureIndexToSubtract]); + } + + private void addSubSub(Accumulator prev, int featureIndexToAdd, int featureIndexToSubtract1, + int featureIndexToSubtract2) + { + featureIndexToAdd = featureIndexToAdd + kingBucket * NNUE.FEATURE_SIZE; + featureIndexToSubtract1 = featureIndexToSubtract1 + kingBucket * NNUE.FEATURE_SIZE; + featureIndexToSubtract2 = featureIndexToSubtract2 + kingBucket * NNUE.FEATURE_SIZE; + + INFERENCE.addSubSub(values, prev.values, network.L1Weights[featureIndexToAdd], + network.L1Weights[featureIndexToSubtract1], network.L1Weights[featureIndexToSubtract2]); + } + + private void addAddSubSub(Accumulator prev, int featureIndexToAdd1, int featureIndexToAdd2, + int featureIndexToSubtract1, int featureIndexToSubtract2) + { + featureIndexToAdd1 = featureIndexToAdd1 + kingBucket * NNUE.FEATURE_SIZE; + featureIndexToAdd2 = featureIndexToAdd2 + kingBucket * NNUE.FEATURE_SIZE; + featureIndexToSubtract1 = featureIndexToSubtract1 + kingBucket * NNUE.FEATURE_SIZE; + featureIndexToSubtract2 = featureIndexToSubtract2 + kingBucket * NNUE.FEATURE_SIZE; + + INFERENCE.addAddSubSub(values, prev.values, network.L1Weights[featureIndexToAdd1], + network.L1Weights[featureIndexToAdd2], network.L1Weights[featureIndexToSubtract1], + network.L1Weights[featureIndexToSubtract2]); + } + + private void efficientlyUpdate(Accumulator prev) + { + final int addedCount = this.diff.getAddedCount(); + final int removedCount = this.diff.getRemovedCount(); + + if (addedCount == 1 && removedCount == 1) + { + final int addedIndex = NNUE.getIndex(this.diff.getAdded(0), this.color); + final int removedIndex = NNUE.getIndex(this.diff.getRemoved(0), this.color); + + this.addSub(prev, addedIndex, removedIndex); + } + + else if (addedCount == 1 && removedCount == 2) + { + final int addedIndex = NNUE.getIndex(this.diff.getAdded(0), this.color); + final int removedIndex0 = NNUE.getIndex(this.diff.getRemoved(0), this.color); + final int removedIndex1 = NNUE.getIndex(this.diff.getRemoved(1), this.color); + + this.addSubSub(prev, addedIndex, removedIndex0, removedIndex1); + } + + else + { + assert addedCount == 2 && removedCount == 2; + + final int addedIndex0 = NNUE.getIndex(this.diff.getAdded(0), this.color); + final int addedIndex1 = NNUE.getIndex(this.diff.getAdded(1), this.color); + final int removedIndex0 = NNUE.getIndex(this.diff.getRemoved(0), this.color); + final int removedIndex1 = NNUE.getIndex(this.diff.getRemoved(1), this.color); + + this.addAddSubSub(prev, addedIndex0, addedIndex1, removedIndex0, removedIndex1); + } + + this.needsRefresh = false; + } + + private void updateFromCache(Board board) + { + AccumulatorCache.Entry entry = cache.get(this.color, NNUE.chooseInputBucket(board, this.color)); + + for (final Side side : Side.values()) + { + for (final PieceType pieceType : PieceType.validValues()) + { + final Piece piece = Piece.make(side, pieceType); + final long oldBB = entry.getBitboard(side, pieceType); + final long newBB = board.getBitboard(side, pieceType); + + long removed = oldBB & ~newBB; + long added = newBB & ~oldBB; + + while (removed != 0L) + { + final Square sq = Square.squareAt(Bitboard.bitScanForward(removed)); + final int featureIndex = NNUE.getIndex(sq, piece, this.color) + kingBucket * NNUE.FEATURE_SIZE; + + INFERENCE.sub(entry.storedAccumulator, entry.storedAccumulator, + network.L1Weights[featureIndex]); + + removed = Bitboard.extractLsb(removed); + } + + while (added != 0L) + { + final Square sq = Square.squareAt(Bitboard.bitScanForward(added)); + final int featureIndex = NNUE.getIndex(sq, piece, this.color) + kingBucket * NNUE.FEATURE_SIZE; + + INFERENCE.add(entry.storedAccumulator, entry.storedAccumulator, + network.L1Weights[featureIndex]); + + added = Bitboard.extractLsb(added); + } + } + } + + System.arraycopy(entry.storedAccumulator, 0, values, 0, NNUE.HIDDEN_SIZE); + + entry.update(board); + + this.needsRefresh = false; + } + + private void makeMove(Accumulator prev, Board board, final AccumulatorDiff diff) + { + this.diff = diff; + this.color = prev.color; + this.needsRefresh = true; + this.kingBucket = NNUE.chooseInputBucket(board, this.color); + } + + private void loadFromBoard(Board board) + { + this.kingBucket = NNUE.chooseInputBucket(board, this.color); + this.needsRefresh = true; + updateFromCache(board); + } + } + + public class AccumulatorPair + { + Accumulator[] accumulators; + + public AccumulatorPair() + { + accumulators = new Accumulator[] { new Accumulator(), new Accumulator() }; + } + + public void init() + { + this.accumulators = new Accumulator[] { new Accumulator(network, Side.WHITE), + new Accumulator(network, Side.BLACK) }; + } + + public void loadFromBoard(Board board) + { + this.accumulators[0].loadFromBoard(board); + this.accumulators[1].loadFromBoard(board); + } + + public void makeMove(AccumulatorPair prev, Board board, Move move, final AccumulatorDiff diff) + { + this.accumulators[0].makeMove(prev.accumulators[0], board, diff); + this.accumulators[1].makeMove(prev.accumulators[1], board, diff); + } + + public Accumulator get(Side side) + { + return this.accumulators[side.ordinal()]; + } + } + + private static final Inference INFERENCE = InferenceChooser.chooseInference(); + private final NNUE network; + private final AccumulatorPair[] stack; + private final AccumulatorCache cache; + private int top; + + public AccumulatorStack(NNUE network) + { + this.network = network; + this.stack = new AccumulatorPair[AlphaBeta.MAX_PLY + 1]; + this.cache = new AccumulatorCache(network); + + for (int i = 0; i < this.stack.length; i++) + { + this.stack[i] = new AccumulatorPair(); + } + } + + public void pop() + { + top--; + } + + public void push(Board board, Move move, final AccumulatorDiff diff) + { + top++; + this.stack[top].makeMove(this.stack[top - 1], board, move, diff); + } + + public void init(Board board) + { + this.top = 0; + this.stack[0].init(); + this.stack[0].loadFromBoard(board); + } + + public void printAccumulator(Side side) + { + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + System.out.print(this.stack[top].accumulators[side.ordinal()].values[i] + ", "); + } + } + + private void efficientlyUpdate(int fromIdx, int toIdx, Side side) + { + for (int i = fromIdx; i < toIdx; i++) + { + Accumulator from = this.stack[i].get(side); + Accumulator to = this.stack[i + 1].get(side); + + assert !from.needsRefresh && to.needsRefresh; + + to.efficientlyUpdate(from); + } + } + + private void refreshAccumulator(Board board, Side side) + { + Accumulator startingAccumulator = this.stack[top].get(side); + + if (!startingAccumulator.needsRefresh) + return; + + int startingKingBucket = startingAccumulator.kingBucket; + + for (int currIdx = top - 1; currIdx >= 0; currIdx--) + { + Accumulator currAccumulator = this.stack[currIdx].get(side); + + if (currAccumulator.kingBucket != startingKingBucket) + break; + + if (!currAccumulator.needsRefresh) + { + efficientlyUpdate(currIdx, top, side); + return; + } + } + + startingAccumulator.updateFromCache(board); + } + + public AccumulatorPair refreshAndGet(Board board) + { + refreshAccumulator(board, Side.WHITE); + refreshAccumulator(board, Side.BLACK); + + return this.stack[top]; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/Inference.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/Inference.java new file mode 100644 index 0000000..a9174f4 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/Inference.java @@ -0,0 +1,39 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.NNUE; + +import org.shawn.games.Serendipity.Chess.Side; + +public interface Inference +{ + int forward(AccumulatorStack.AccumulatorPair accumulators, Side side, final short[] weights, final short bias); + + void add(short[] to, final short[] from, final short[] added); + + void sub(short[] to, final short[] from, final short[] removed); + + void addSub(short[] to, final short[] from, final short[] added, final short[] subtracted); + + void addSubSub(short[] to, final short[] from, final short[] added, final short[] subtracted1, + final short[] subtracted2); + + void addAddSubSub(short[] to, final short[] from, final short[] added1, final short[] added2, + final short[] subtracted1, final short[] subtracted2); +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/InferenceChooser.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/InferenceChooser.java new file mode 100644 index 0000000..c8f478c --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/InferenceChooser.java @@ -0,0 +1,35 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.NNUE; + +import jdk.incubator.vector.ShortVector; + +public class InferenceChooser +{ + public static Inference chooseInference() + { + if (ShortVector.SPECIES_PREFERRED.vectorBitSize() >= 256) + { + return new SIMDInference(); + } + + return new ScalarInference(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/NNUE.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/NNUE.java new file mode 100644 index 0000000..59447f0 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/NNUE.java @@ -0,0 +1,168 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.NNUE; + +import java.io.*; +import java.util.Objects; + +import org.shawn.games.Serendipity.Chess.*; + +public class NNUE +{ + private static final int COLOR_STRIDE = 64 * 6; + private static final int PIECE_STRIDE = 64; + + static final int HIDDEN_SIZE = 1536; + static final int FEATURE_SIZE = 768; + static final int OUTPUT_BUCKETS = 8; + private static final int DIVISOR = (32 + OUTPUT_BUCKETS - 1) / OUTPUT_BUCKETS; + static final int INPUT_BUCKET_SIZE = 7; + // @formatter:off + private static final int[] INPUT_BUCKETS = new int[] + { + 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + }; + // @formatter:on + + public static final int SCALE = 400; + public static final int QA = 255; + public static final int QB = 64; + + final short[][] L1Weights; + final short[] L1Biases; + private final short[][] L2Weights; + private final short[] outputBiases; + + private static final Inference INFERENCE = InferenceChooser.chooseInference(); + + private short toLittleEndian(short input) + { + return (short) (((input & 0xFF) << 8) | ((input & 0xFF00) >> 8)); + } + + public NNUE(String filePath) throws IOException + { + DataInputStream networkData = new DataInputStream( + Objects.requireNonNull(getClass().getResourceAsStream(filePath))); + + L1Weights = new short[FEATURE_SIZE * INPUT_BUCKET_SIZE][HIDDEN_SIZE]; + + for (int i = 0; i < FEATURE_SIZE * INPUT_BUCKET_SIZE; i++) + { + for (int j = 0; j < HIDDEN_SIZE; j++) + { + L1Weights[i][j] = toLittleEndian(networkData.readShort()); + } + } + + L1Biases = new short[HIDDEN_SIZE]; + + for (int i = 0; i < HIDDEN_SIZE; i++) + { + L1Biases[i] = toLittleEndian(networkData.readShort()); + } + + L2Weights = new short[OUTPUT_BUCKETS][HIDDEN_SIZE * 2]; + + for (int i = 0; i < HIDDEN_SIZE * 2; i++) + { + for (int j = 0; j < OUTPUT_BUCKETS; j++) + { + L2Weights[j][i] = toLittleEndian(networkData.readShort()); + } + } + + outputBiases = new short[OUTPUT_BUCKETS]; + + for (int i = 0; i < OUTPUT_BUCKETS; i++) + { + outputBiases[i] = toLittleEndian(networkData.readShort()); + } + + networkData.close(); + } + + public static int chooseOutputBucket(Board board) + { + return (Long.bitCount(board.getBitboard()) - 2) / DIVISOR; + } + + public static int evaluate(Board board, NNUE network, AccumulatorStack accumulators) + { + final int chosenBucket = chooseOutputBucket(board); + + return INFERENCE.forward(accumulators.refreshAndGet(board), board.getSideToMove(), + network.L2Weights[chosenBucket], network.outputBiases[chosenBucket]); + } + + public static int chooseInputBucket(Board board, Side side) + { + return side.equals(Side.WHITE) ? INPUT_BUCKETS[board.getKingSquare(side).ordinal()] + : INPUT_BUCKETS[board.getKingSquare(side).ordinal() ^ 0b111000]; + } + + public static int chooseInputBucket(Square square, Side side) + { + return side.equals(Side.WHITE) ? INPUT_BUCKETS[square.ordinal()] : INPUT_BUCKETS[square.ordinal() ^ 0b111000]; + } + + public static int getIndex(Square square, Piece piece, Side perspective) + { + return Side.WHITE.equals(perspective) + ? piece.getPieceSide().ordinal() * COLOR_STRIDE + piece.getPieceType().ordinal() * PIECE_STRIDE + + square.ordinal() + : (piece.getPieceSide().ordinal() ^ 1) * COLOR_STRIDE + piece.getPieceType().ordinal() * PIECE_STRIDE + + (square.ordinal() ^ 0b111000); + } + + public static int getIndex(final AccumulatorDiff.DiffInfo diff, Side perspective) + { + return getIndex(diff.square, diff.piece, perspective); + } + + public static boolean requiresRefresh(final AccumulatorDiff diff, Side perspective) + { + assert diff.getAddedCount() <= 1 || !diff.getAdded(1).piece.getPieceType().equals(PieceType.KING); + + if (!diff.getAdded(0).piece.getPieceType().equals(PieceType.KING)) + { + return false; + } + + if (!diff.getAdded(0).piece.getPieceSide().equals(perspective)) + { + return false; + } + + assert diff.getRemoved(0).piece.getPieceType().equals(PieceType.KING); + + final Square prevKing = diff.getRemoved(0).square; + final Square currKing = diff.getAdded(0).square; + + return chooseInputBucket(prevKing, perspective) != chooseInputBucket(currKing, perspective); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/SIMDInference.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/SIMDInference.java new file mode 100644 index 0000000..9e5c0a5 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/SIMDInference.java @@ -0,0 +1,151 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.NNUE; + +import static jdk.incubator.vector.VectorOperators.S2I; + +import org.shawn.games.Serendipity.Chess.Side; + +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorOperators; +import jdk.incubator.vector.VectorSpecies; + +public class SIMDInference implements Inference +{ + private static final VectorSpecies SHORT_SPECIES = ShortVector.SPECIES_PREFERRED; + private static final int UPPERBOUND = SHORT_SPECIES.loopBound(NNUE.HIDDEN_SIZE); + + @Override + public int forward(AccumulatorStack.AccumulatorPair accumulators, Side side, short[] weights, short bias) + { + AccumulatorStack.Accumulator us = accumulators.get(side); + AccumulatorStack.Accumulator them = accumulators.get(side.flip()); + + IntVector sum = IntVector.zero(SHORT_SPECIES.vectorShape().withLanes(int.class)); + + for (int i = 0; i < UPPERBOUND; i += SHORT_SPECIES.length()) + { + ShortVector usInputs = ShortVector.fromArray(SHORT_SPECIES, us.values, i); + ShortVector themInputs = ShortVector.fromArray(SHORT_SPECIES, them.values, i); + ShortVector usWeights = ShortVector.fromArray(SHORT_SPECIES, weights, i); + ShortVector themWeights = ShortVector.fromArray(SHORT_SPECIES, weights, i + NNUE.HIDDEN_SIZE); + + usInputs = usInputs.max(ShortVector.zero(SHORT_SPECIES)).min(ShortVector.broadcast(SHORT_SPECIES, NNUE.QA)); + themInputs = themInputs.max(ShortVector.zero(SHORT_SPECIES)) + .min(ShortVector.broadcast(SHORT_SPECIES, NNUE.QA)); + + ShortVector usWeightedTerms = usInputs.mul(usWeights); + ShortVector themWeightedTerms = themInputs.mul(themWeights); + + Vector usInputsLo = usInputs.convert(S2I, 0); + Vector usInputsHi = usInputs.convert(S2I, 1); + Vector themInputsLo = themInputs.convert(S2I, 0); + Vector themInputsHi = themInputs.convert(S2I, 1); + + Vector usWeightedTermsLo = usWeightedTerms.convert(S2I, 0); + Vector usWeightedTermsHi = usWeightedTerms.convert(S2I, 1); + Vector themWeightedTermsLo = themWeightedTerms.convert(S2I, 0); + Vector themWeightedTermsHi = themWeightedTerms.convert(S2I, 1); + + sum = sum.add(usInputsLo.mul(usWeightedTermsLo)).add(usInputsHi.mul(usWeightedTermsHi)) + .add(themInputsLo.mul(themWeightedTermsLo)).add(themInputsHi.mul(themWeightedTermsHi)); + } + + int eval = sum.reduceLanes(VectorOperators.ADD); + + eval /= NNUE.QA; + eval += bias; + + eval *= NNUE.SCALE; + eval /= NNUE.QA * NNUE.QB; + + return eval; + } + + @Override + public void add(short[] to, final short[] from, final short[] added) + { + for (int i = 0; i < UPPERBOUND; i += SHORT_SPECIES.length()) + { + final ShortVector fromVector = ShortVector.fromArray(SHORT_SPECIES, from, i); + final ShortVector addVector = ShortVector.fromArray(SHORT_SPECIES, added, i); + + fromVector.add(addVector).intoArray(to, i); + } + } + + @Override + public void sub(short[] to, final short[] from, final short[] removed) + { + for (int i = 0; i < UPPERBOUND; i += SHORT_SPECIES.length()) + { + final ShortVector fromVector = ShortVector.fromArray(SHORT_SPECIES, from, i); + final ShortVector subVector = ShortVector.fromArray(SHORT_SPECIES, removed, i); + + fromVector.sub(subVector).intoArray(to, i); + } + } + + @Override + public void addSub(short[] to, final short[] from, final short[] added, final short[] subtracted) + { + for (int i = 0; i < UPPERBOUND; i += SHORT_SPECIES.length()) + { + final ShortVector fromVector = ShortVector.fromArray(SHORT_SPECIES, from, i); + final ShortVector addVector = ShortVector.fromArray(SHORT_SPECIES, added, i); + final ShortVector subVector = ShortVector.fromArray(SHORT_SPECIES, subtracted, i); + + fromVector.add(addVector).sub(subVector).intoArray(to, i); + } + } + + @Override + public void addSubSub(short[] to, final short[] from, final short[] added, final short[] subtracted1, + final short[] subtracted2) + { + for (int i = 0; i < UPPERBOUND; i += SHORT_SPECIES.length()) + { + final ShortVector fromVector = ShortVector.fromArray(SHORT_SPECIES, from, i); + final ShortVector addVector = ShortVector.fromArray(SHORT_SPECIES, added, i); + final ShortVector subVector1 = ShortVector.fromArray(SHORT_SPECIES, subtracted1, i); + final ShortVector subVector2 = ShortVector.fromArray(SHORT_SPECIES, subtracted2, i); + + fromVector.add(addVector).sub(subVector1).sub(subVector2).intoArray(to, i); + } + } + + @Override + public void addAddSubSub(short[] to, final short[] from, final short[] added1, final short[] added2, + final short[] subtracted1, final short[] subtracted2) + { + for (int i = 0; i < UPPERBOUND; i += SHORT_SPECIES.length()) + { + final ShortVector fromVector = ShortVector.fromArray(SHORT_SPECIES, from, i); + final ShortVector addVector1 = ShortVector.fromArray(SHORT_SPECIES, added1, i); + final ShortVector addVector2 = ShortVector.fromArray(SHORT_SPECIES, added2, i); + final ShortVector subVector1 = ShortVector.fromArray(SHORT_SPECIES, subtracted1, i); + final ShortVector subVector2 = ShortVector.fromArray(SHORT_SPECIES, subtracted2, i); + + fromVector.add(addVector1).add(addVector2).sub(subVector1).sub(subVector2).intoArray(to, i); + } + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/ScalarInference.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/ScalarInference.java new file mode 100644 index 0000000..cefa10d --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/ScalarInference.java @@ -0,0 +1,111 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.NNUE; + +import org.shawn.games.Serendipity.Chess.Side; + +public class ScalarInference implements Inference +{ + private final static int[] screlu = new int[Short.MAX_VALUE - Short.MIN_VALUE + 1]; + + static + { + for (int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) + { + screlu[i - (int) Short.MIN_VALUE] = screlu((short) (i)); + } + } + + private static int screlu(short i) + { + int v = Math.max(0, Math.min(i, NNUE.QA)); + return v * v; + } + + @Override + public int forward(AccumulatorStack.AccumulatorPair accumulators, Side side, short[] weights, short bias) + { + int eval = 0; + + AccumulatorStack.Accumulator us = accumulators.get(side); + AccumulatorStack.Accumulator them = accumulators.get(side.flip()); + + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + eval += screlu[us.values[i] - (int) Short.MIN_VALUE] * (int) weights[i] + + screlu[them.values[i] - (int) Short.MIN_VALUE] * (int) weights[i + NNUE.HIDDEN_SIZE]; + } + + eval /= NNUE.QA; + eval += bias; + + eval *= NNUE.SCALE; + eval /= NNUE.QA * NNUE.QB; + + return eval; + } + + @Override + public void add(short[] to, final short[] from, final short[] added) + { + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + to[i] = (short) (from[i] + added[i]); + } + } + + @Override + public void sub(short[] to, final short[] from, final short[] removed) + { + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + to[i] = (short) (from[i] - removed[i]); + } + } + + @Override + public void addSub(short[] to, final short[] from, final short[] added, final short[] subtracted) + { + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + to[i] = (short) (from[i] + added[i] - subtracted[i]); + } + } + + @Override + public void addSubSub(short[] to, final short[] from, final short[] added, final short[] subtracted1, + final short[] subtracted2) + { + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + to[i] = (short) (from[i] + added[i] - subtracted1[i] - subtracted2[i]); + } + } + + @Override + public void addAddSubSub(short[] to, final short[] from, final short[] added1, final short[] added2, + final short[] subtracted1, final short[] subtracted2) + { + for (int i = 0; i < NNUE.HIDDEN_SIZE; i++) + { + to[i] = (short) (from[i] + added1[i] + added2[i] - subtracted1[i] - subtracted2[i]); + } + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/module-info.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/module-info.java new file mode 100644 index 0000000..733505e --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/NNUE/module-info.java @@ -0,0 +1,24 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +module org.shawn.games.Serendipity.NNUE +{ + requires jdk.incubator.vector; + requires org.apache.commons.lang3; +} \ No newline at end of file diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/PeSTO/PeSTO.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/PeSTO/PeSTO.java new file mode 100644 index 0000000..204dae8 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/PeSTO/PeSTO.java @@ -0,0 +1,381 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.PeSTO; + +import org.shawn.games.Serendipity.Chess.*; + +public class PeSTO +{ + // @formatter:off + final static int[] MG_PAWN_TABLE = new int[] + { + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 134, 61, 95, 68, 126, 34, -11, + -6, 7, 26, 31, 65, 56, 25, -20, + -14, 13, 6, 21, 23, 12, 17, -23, + -27, -2, -5, 12, 17, 6, 10, -25, + -26, -4, -4, -10, 3, 3, 33, -12, + -35, -1, -20, -23, -15, 24, 38, -22, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + final static int[] EG_PAWN_TABLE = new int[] + { + 0, 0, 0, 0, 0, 0, 0, 0, + 178, 173, 158, 134, 147, 132, 165, 187, + 94, 100, 85, 67, 56, 53, 82, 84, + 32, 24, 13, 5, -2, 4, 17, 17, + 13, 9, -3, -7, -7, -8, 3, -1, + 4, 7, -6, 1, 0, -5, -1, -8, + 13, 8, 8, 10, 13, 0, 2, -7, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + final static int[] MG_KNIGHT_TABLE = new int[] + { + -167, -89, -34, -49, 61, -97, -15, -107, + -73, -41, 72, 36, 23, 62, 7, -17, + -47, 60, 37, 65, 84, 129, 73, 44, + -9, 17, 19, 53, 37, 69, 18, 22, + -13, 4, 16, 13, 28, 19, 21, -8, + -23, -9, 12, 10, 19, 17, 25, -16, + -29, -53, -12, -3, -1, 18, -14, -19, + -105, -21, -58, -33, -17, -28, -19, -23, + }; + + final static int[] EG_KNIGHT_TABLE = new int[] + { + -58, -38, -13, -28, -31, -27, -63, -99, + -25, -8, -25, -2, -9, -25, -24, -52, + -24, -20, 10, 9, -1, -9, -19, -41, + -17, 3, 22, 22, 22, 11, 8, -18, + -18, -6, 16, 25, 16, 17, 4, -18, + -23, -3, -1, 15, 10, -3, -20, -22, + -42, -20, -10, -5, -2, -20, -23, -44, + -29, -51, -23, -15, -22, -18, -50, -64, + }; + + final static int[] MG_BISHOP_TABLE = new int[] + { + -29, 4, -82, -37, -25, -42, 7, -8, + -26, 16, -18, -13, 30, 59, 18, -47, + -16, 37, 43, 40, 35, 50, 37, -2, + -4, 5, 19, 50, 37, 37, 7, -2, + -6, 13, 13, 26, 34, 12, 10, 4, + 0, 15, 15, 15, 14, 27, 18, 10, + 4, 15, 16, 0, 7, 21, 33, 1, + -33, -3, -14, -21, -13, -12, -39, -21, + }; + + final static int[] EG_BISHOP_TABLE = new int[] + { + -14, -21, -11, -8, -7, -9, -17, -24, + -8, -4, 7, -12, -3, -13, -4, -14, + 2, -8, 0, -1, -2, 6, 0, 4, + -3, 9, 12, 9, 14, 10, 3, 2, + -6, 3, 13, 19, 7, 10, -3, -9, + -12, -3, 8, 10, 13, 3, -7, -15, + -14, -18, -7, -1, 4, -9, -15, -27, + -23, -9, -23, -5, -9, -16, -5, -17, + }; + + final static int[] MG_ROOK_TABLE = new int[] + { + 32, 42, 32, 51, 63, 9, 31, 43, + 27, 32, 58, 62, 80, 67, 26, 44, + -5, 19, 26, 36, 17, 45, 61, 16, + -24, -11, 7, 26, 24, 35, -8, -20, + -36, -26, -12, -1, 9, -7, 6, -23, + -45, -25, -16, -17, 3, 0, -5, -33, + -44, -16, -20, -9, -1, 11, -6, -71, + -19, -13, 1, 17, 16, 7, -37, -26, + }; + + final static int[] EG_ROOK_TABLE = new int[] + { + 13, 10, 18, 15, 12, 12, 8, 5, + 11, 13, 13, 11, -3, 3, 8, 3, + 7, 7, 7, 5, 4, -3, -5, -3, + 4, 3, 13, 1, 2, 1, -1, 2, + 3, 5, 8, 4, -5, -6, -8, -11, + -4, 0, -5, -1, -7, -12, -8, -16, + -6, -6, 0, 2, -9, -9, -11, -3, + -9, 2, 3, -1, -5, -13, 4, -20, + }; + + final static int[] MG_QUEEN_TABLE = new int[] + { + -28, 0, 29, 12, 59, 44, 43, 45, + -24, -39, -5, 1, -16, 57, 28, 54, + -13, -17, 7, 8, 29, 56, 47, 57, + -27, -27, -16, -16, -1, 17, -2, 1, + -9, -26, -9, -10, -2, -4, 3, -3, + -14, 2, -11, -2, -5, 2, 14, 5, + -35, -8, 11, 2, 8, 15, -3, 1, + -1, -18, -9, 10, -15, -25, -31, -50, + }; + + final static int[] EG_QUEEN_TABLE = new int[] + { + -9, 22, 22, 27, 27, 19, 10, 20, + -17, 20, 32, 41, 58, 25, 30, 0, + -20, 6, 9, 49, 47, 35, 19, 9, + 3, 22, 24, 45, 57, 40, 57, 36, + -18, 28, 19, 47, 31, 34, 39, 23, + -16, -27, 15, 6, 9, 17, 10, 5, + -22, -23, -30, -16, -16, -23, -36, -32, + -33, -28, -22, -43, -5, -32, -20, -41, + }; + + final static int[] MG_KING_TABLE = new int[] + { + -65, 23, 16, -15, -56, -34, 2, 13, + 29, -1, -20, -7, -8, -4, -38, -29, + -9, 24, 2, -16, -20, 6, 22, -22, + -17, -20, -12, -27, -30, -25, -14, -36, + -49, -1, -27, -39, -46, -44, -33, -51, + -14, -14, -22, -46, -44, -30, -15, -27, + 1, 7, -8, -64, -43, -16, 9, 8, + -15, 36, 12, -54, 8, -28, 24, 14, + }; + + final static int[] EG_KING_TABLE = new int[] + { + -74, -35, -18, -18, -11, 15, 4, -17, + -12, 17, 14, 17, 17, 38, 23, 11, + 10, 17, 23, 15, 20, 45, 44, 13, + -8, 22, 24, 27, 26, 33, 26, 3, + -18, -4, 21, 24, 27, 23, 9, -11, + -19, -3, 11, 21, 23, 16, 7, -9, + -27, -11, 4, 13, 14, 4, -5, -17, + -53, -34, -21, -11, -28, -14, -24, -43 + }; + + final static int[] MIRRORED_SQUARE_VALUE = new int[] + { + 56, 57, 58, 59, 60, 61, 62, 63, + 48, 49, 50, 51, 52, 53, 54, 55, + 40, 41, 42, 43, 44, 45, 46, 47, + 32, 33, 34, 35, 36, 37, 38, 39, + 24, 25, 26, 27, 28, 29, 30, 31, + 16, 17, 18, 19, 20, 21, 22, 23, + 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7 + }; + // @formatter:on + + final static int MG_PAWN_VALUE = 82; + final static int MG_KNIGHT_VALUE = 337; + final static int MG_BISHOP_VALUE = 365; + final static int MG_ROOK_VALUE = 477; + final static int MG_QUEEN_VALUE = 1025; + + final static int EG_PAWN_VALUE = 94; + final static int EG_KNIGHT_VALUE = 281; + final static int EG_BISHOP_VALUE = 297; + final static int EG_ROOK_VALUE = 512; + final static int EG_QUEEN_VALUE = 936; + + final static int PAWN_PHASE = 0; + final static int KNIGHT_PHASE = 1; + final static int BISHOP_PHASE = 1; + final static int ROOK_PHASE = 2; + final static int QUEEN_PHASE = 4; + + final static int TEMPO = 8; + + final static int MAX_PHASE = KNIGHT_PHASE * 4 + BISHOP_PHASE * 4 + ROOK_PHASE * 4 + QUEEN_PHASE * 2; + + private static int getIndex(Side side, Square square) + { + return side == Side.BLACK ? square.ordinal() : MIRRORED_SQUARE_VALUE[square.ordinal()]; + } + + private static int pieceMiddleGameValue(Piece piece, Square square) + { + switch (piece.getPieceType()) + { + case PAWN: + return MG_PAWN_TABLE[getIndex(piece.getPieceSide(), square)] + MG_PAWN_VALUE; + case KNIGHT: + return MG_KNIGHT_TABLE[getIndex(piece.getPieceSide(), square)] + MG_KNIGHT_VALUE; + case BISHOP: + return MG_BISHOP_TABLE[getIndex(piece.getPieceSide(), square)] + MG_BISHOP_VALUE; + case ROOK: + return MG_ROOK_TABLE[getIndex(piece.getPieceSide(), square)] + MG_ROOK_VALUE; + case QUEEN: + return MG_QUEEN_TABLE[getIndex(piece.getPieceSide(), square)] + MG_QUEEN_VALUE; + case KING: + return MG_KING_TABLE[getIndex(piece.getPieceSide(), square)]; + default: + return 0; + + } + } + + private static int pieceEndGameValue(Piece piece, Square square) + { + switch (piece.getPieceType()) + { + case PAWN: + return EG_PAWN_TABLE[getIndex(piece.getPieceSide(), square)] + EG_PAWN_VALUE; + case KNIGHT: + return EG_KNIGHT_TABLE[getIndex(piece.getPieceSide(), square)] + EG_KNIGHT_VALUE; + case BISHOP: + return EG_BISHOP_TABLE[getIndex(piece.getPieceSide(), square)] + EG_BISHOP_VALUE; + case ROOK: + return EG_ROOK_TABLE[getIndex(piece.getPieceSide(), square)] + EG_ROOK_VALUE; + case QUEEN: + return EG_QUEEN_TABLE[getIndex(piece.getPieceSide(), square)] + EG_QUEEN_VALUE; + case KING: + return EG_KING_TABLE[getIndex(piece.getPieceSide(), square)]; + default: + return 0; + + } + } + + private static int middleGameEval(Board board) + { + long pieces = board.getBitboard(board.getSideToMove()); + + int score = 0; + + while (pieces != 0) + { + Square square = Square.squareAt(Bitboard.bitScanForward(pieces)); + pieces = Bitboard.extractLsb(pieces); + score += pieceMiddleGameValue(board.getPiece(square), square); + } + + pieces = board.getBitboard(board.getSideToMove().flip()); + + while (pieces != 0) + { + Square square = Square.squareAt(Bitboard.bitScanForward(pieces)); + pieces = Bitboard.extractLsb(pieces); + score -= pieceMiddleGameValue(board.getPiece(square), square); + } + + return score; + } + + private static int endGameEval(Board board) + { + long pieces = board.getBitboard(board.getSideToMove()); + + int score = 0; + + while (pieces != 0) + { + Square square = Square.squareAt(Bitboard.bitScanForward(pieces)); + pieces = Bitboard.extractLsb(pieces); + score += pieceEndGameValue(board.getPiece(square), square); + } + + pieces = board.getBitboard(board.getSideToMove().flip()); + + while (pieces != 0) + { + Square square = Square.squareAt(Bitboard.bitScanForward(pieces)); + pieces = Bitboard.extractLsb(pieces); + score -= pieceEndGameValue(board.getPiece(square), square); + } + + return score; + } + + private static int gamePhase(Board board) + { + Side ourSide = board.getSideToMove(); + Side opposite = board.getSideToMove().flip(); + // @formatter:off + return Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.PAWN))) * PAWN_PHASE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.KNIGHT))) * KNIGHT_PHASE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.BISHOP))) * BISHOP_PHASE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.ROOK))) * ROOK_PHASE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.QUEEN))) * QUEEN_PHASE + + Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.PAWN))) * PAWN_PHASE + + Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.KNIGHT))) * KNIGHT_PHASE + + Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.BISHOP))) * BISHOP_PHASE + + Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.ROOK))) * ROOK_PHASE + + Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.QUEEN))) * QUEEN_PHASE; + // @formatter:on + } + + private static int middleGameMaterialEval(Board board) + { + + Side ourSide = board.getSideToMove(); + Side opposite = board.getSideToMove().flip(); + // @formatter:off + return Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.PAWN))) * MG_PAWN_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.KNIGHT))) * MG_KNIGHT_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.BISHOP))) * MG_BISHOP_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.ROOK))) * MG_ROOK_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.QUEEN))) * MG_QUEEN_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.PAWN))) * MG_PAWN_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.KNIGHT))) * MG_KNIGHT_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.BISHOP))) * MG_BISHOP_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.ROOK))) * MG_ROOK_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.QUEEN))) * MG_QUEEN_VALUE; + // @formatter:on + } + + private static int endGameMaterialEval(Board board) + { + + Side ourSide = board.getSideToMove(); + Side opposite = board.getSideToMove().flip(); + // @formatter:off + return Long.bitCount(board.getBitboard(Piece.make(board.getSideToMove(), PieceType.PAWN))) * EG_PAWN_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.KNIGHT))) * EG_KNIGHT_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.BISHOP))) * EG_BISHOP_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.ROOK))) * EG_ROOK_VALUE + + Long.bitCount(board.getBitboard(Piece.make(ourSide, PieceType.QUEEN))) * EG_QUEEN_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.PAWN))) * EG_PAWN_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.KNIGHT))) * EG_KNIGHT_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.BISHOP))) * EG_BISHOP_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.ROOK))) * EG_ROOK_VALUE + - Long.bitCount(board.getBitboard(Piece.make(opposite, PieceType.QUEEN))) * EG_QUEEN_VALUE; + // @formatter:on + } + + private static int bishopPairAdjustment(Board board) + { + return (Long.bitCount(board.getBitboard(Piece.make(board.getSideToMove(), PieceType.BISHOP))) == 2 ? 720 : 0) + - (Long.bitCount(board.getBitboard(Piece.make(board.getSideToMove().flip(), PieceType.BISHOP))) == 2 + ? 720 + : 0); + } + + public static int materialEval(Board board) + { + int gamePhase = Math.min(MAX_PHASE, gamePhase(board)); + return middleGameMaterialEval(board) * gamePhase + endGameMaterialEval(board) * (MAX_PHASE - gamePhase); + } + + public static int evaluate(Board board) + { + int gamePhase = Math.min(MAX_PHASE, gamePhase(board)); + return middleGameEval(board) * gamePhase + endGameEval(board) * (MAX_PHASE - gamePhase) + + bishopPairAdjustment(board) + TEMPO * MAX_PHASE; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/AlphaBeta.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/AlphaBeta.java new file mode 100644 index 0000000..e99963f --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/AlphaBeta.java @@ -0,0 +1,956 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import java.util.*; +import java.util.concurrent.BrokenBarrierException; + +import org.shawn.games.Serendipity.NNUE.*; +import org.shawn.games.Serendipity.Search.Debug.Debugger; +import org.shawn.games.Serendipity.Search.History.History; +import org.shawn.games.Serendipity.Search.Listener.FinalReport; +import org.shawn.games.Serendipity.Search.Listener.ISearchListener; +import org.shawn.games.Serendipity.Search.Listener.SearchReport; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.*; + +public class AlphaBeta implements Runnable +{ + public static final int VALUE_NONE = 30002; + public static final int MAX_EVAL = 32767; + public static final int MIN_EVAL = -32767; + public static final int MATE_EVAL = 32700; + public static final int DRAW_EVAL = 0; + public static final int MAX_PLY = 245; + + public static final int MATE_IN_MAX_PLY = MATE_EVAL - MAX_PLY; + + public final int[][] reduction = new int[MAX_PLY + 1][MAX_PLY + 1]; + + private int nmpMinPly; + + private AccumulatorStack accumulators; + + private final ThreadData threadData; + private final SharedThreadData sharedThreadData; + private SearchStack ss; + private TimeManager timeManager; + + private Board internalBoard; + + private Move bestMove; + + public AlphaBeta(SharedThreadData sharedThreadData, ThreadData threadData) + { + this.ss = new SearchStack(MAX_PLY); + + this.sharedThreadData = sharedThreadData; + this.threadData = threadData; + + if (threadData.id == 0) + { + this.timeManager = new TimeManager(); + } + + for (int i = 0; i < reduction.length; i++) + { + for (int j = 0; j < reduction[0].length; j++) + { + reduction[i][j] = (int) (1.60 + Math.log(i) * Math.log(j) / 2.17); + } + } + } + + private void updatePV(Move move, int ply) + { + threadData.pv[ply][0] = move; + System.arraycopy(threadData.pv[ply + 1], 0, threadData.pv[ply], 1, MAX_PLY); + } + + private void clearPV() + { + this.threadData.pv = new Move[MAX_PLY + 1][MAX_PLY + 1]; + } + + private static int stat_bonus(int depth) + { + return depth * 300 - 300; + } + + private static int stat_malus(int depth) + { + return -stat_bonus(depth); + } + + private boolean shouldStop() + { + return (this.threadData.id == 0 && this.threadData.mainThreadData.limits.getNodes() > 0 + && this.threadData.nodes.get() > threadData.mainThreadData.limits.getNodes()) + || sharedThreadData.stopped.get() || (this.threadData.id == 0 && this.timeManager.shouldStop()); + } + + public int evaluate(Board board) + { + int v = NNUE.evaluate(board, sharedThreadData.network, accumulators); + + final int material = Long + .bitCount(board.getBitboard(Piece.WHITE_BISHOP) | board.getBitboard(Piece.BLACK_BISHOP)) * 3 + + Long.bitCount(board.getBitboard(Piece.WHITE_KNIGHT) | board.getBitboard(Piece.BLACK_KNIGHT)) * 3 + + Long.bitCount(board.getBitboard(Piece.WHITE_ROOK) | board.getBitboard(Piece.BLACK_ROOK)) * 5 + + Long.bitCount(board.getBitboard(Piece.WHITE_QUEEN) | board.getBitboard(Piece.BLACK_QUEEN)) * 10; + + v = v * (206 + material) / 256; + + v = Math.min(Math.max(-MATE_IN_MAX_PLY, v), MATE_IN_MAX_PLY); + + return v; + } + + private void updateContinuationHistories(int ply, int depth, Board board, Move move, List quietsSearched) + { + History conthist; + int bonus = stat_bonus(depth); + int malus = stat_malus(depth); + + for (int i : new int[] { 1, 2, 4, 6 }) + { + conthist = ss.get(ply - i).continuationHistory; + + conthist.register(board, move, (i == 6) ? bonus / 2 : bonus); + + for (Move quietMove : quietsSearched) + { + conthist.register(board, quietMove, (i == 6) ? malus / 2 : malus); + } + } + } + + private int quiesce(Board board, int alpha, int beta, int ply) throws TimeOutException + { + this.threadData.nodes.incrementAndGet(); + + this.threadData.selDepth = Math.max(this.threadData.selDepth, ply); + + SearchStack.SearchState sse = ss.get(ply); + + int bestScore; + + if (board.isRepetition() || board.getHalfMoveCounter() > 100) + { + return DRAW_EVAL; + } + + if ((this.threadData.nodes.get() & 1023) == 0 && this.shouldStop()) + { + if (threadData.id == 0) + { + sharedThreadData.stopped.set(true); + } + + throw new TimeOutException(); + } + + boolean isPV = beta - alpha > 1; + final int oldAlpha = alpha; + + TranspositionTable.Entry currentMoveEntry = sharedThreadData.tt.probe(board.getIncrementalHashKey()); + boolean ttHit = currentMoveEntry.hit() && currentMoveEntry.verifySignature(board.getIncrementalHashKey()); + final boolean ttPV = isPV | (currentMoveEntry.hit() && currentMoveEntry.wasPV()); + final Move ttMove = ttHit ? currentMoveEntry.getMove() : null; + + if (!isPV && ttHit && currentMoveEntry.getNodeType() != TranspositionTable.NODETYPE_NONE) + { + int eval = currentMoveEntry.getEvaluation(); + switch (currentMoveEntry.getNodeType()) + { + case TranspositionTable.NODETYPE_EXACT: + return eval; + case TranspositionTable.NODETYPE_UPPERBOUND: + if (eval <= alpha) + { + return eval; + } + break; + case TranspositionTable.NODETYPE_LOWERBOUND: + if (eval >= beta) + { + return eval; + } + break; + default: + ttHit = false; // TT write race + } + } + + if (ply >= MAX_PLY) + { + return evaluate(board); + } + + int futilityBase; + boolean inCheck = sse.inCheck = board.isKingAttacked(); + + MovePicker movePicker; + + if (inCheck) + { + bestScore = futilityBase = MIN_EVAL; + + History[] currentContinuationHistories = new History[] { ss.get(ply - 1).continuationHistory, + ss.get(ply - 2).continuationHistory, null, ss.get(ply - 4).continuationHistory, null, + ss.get(ply - 6).continuationHistory }; + + movePicker = new MovePicker(board, ttMove, null, threadData.history, threadData.captureHistory, + currentContinuationHistories); + } + + else + { + if (ttHit) + { + bestScore = sse.staticEval = currentMoveEntry.getStaticEval(); + } + + else + { + bestScore = sse.staticEval = evaluate(board); + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_NONE, TranspositionTable.DEPTH_NONE, VALUE_NONE, null, + sse.staticEval, ttPV); + } + + alpha = Math.max(alpha, sse.staticEval); + + if (alpha >= beta) + { + return alpha; + } + + futilityBase = sse.staticEval + 205; + movePicker = new MovePicker(board, ttMove, threadData.captureHistory); + } + + Move move; + + while ((move = movePicker.next()) != null) + { + if (!board.isMoveLegal(move, false)) + { + continue; + } + + if (bestScore > -MATE_IN_MAX_PLY && futilityBase < alpha && !board.staticExchangeEvaluation(move, 1) + && board.hasNonPawnMaterial()) + { + bestScore = Math.max(bestScore, futilityBase); + continue; + } + + if (!inCheck && !board.staticExchangeEvaluation(move, -20)) + { + continue; + } + + AccumulatorDiff diff = board.doMove(move); + accumulators.push(board, move, diff); + sse.move = move; + sse.continuationHistory = threadData.continuationHistories.get(board, sse.move); + + int score = -quiesce(board, -beta, -alpha, ply + 1); + + board.undoMove(); + accumulators.pop(); + + bestScore = Math.max(bestScore, score); + alpha = Math.max(alpha, bestScore); + + if (alpha >= beta) + { + break; + } + } + + if (bestScore == MIN_EVAL && inCheck) + { + return -MATE_EVAL + ply; + } + + if (alpha >= oldAlpha) + { + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_LOWERBOUND, TranspositionTable.DEPTH_QS, bestScore, bestMove, + sse.staticEval, ttPV); + } + + else + { + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_UPPERBOUND, TranspositionTable.DEPTH_QS, bestScore, ttMove, + sse.staticEval, ttPV); + } + + return bestScore; + } + + private int mainSearch(Board board, int depth, int alpha, int beta, int ply, boolean cutNode) + throws TimeOutException + { + this.threadData.nodes.incrementAndGet(); + this.ss.get(ply + 2).killer = null; + this.threadData.selDepth = Math.max(this.threadData.selDepth, ply); + + boolean improving, isPV, inCheck, inSingularSearch; + boolean ttPV, ttCapture; + Move bestMove, ttMove; + int bestValue; + int eval; + + SearchStack.SearchState sse = ss.get(ply); + + bestValue = MIN_EVAL; + bestMove = null; + sse.moveCount = 0; + isPV = beta - alpha > 1; + inCheck = sse.inCheck = board.isKingAttacked(); + inSingularSearch = sse.excludedMove != null; + + if (isPV) + { + threadData.pv[ply][0] = null; + } + + if ((this.threadData.nodes.get() & 1023) == 0 && this.shouldStop()) + { + if (threadData.id == 0) + { + sharedThreadData.stopped.set(true); + } + + throw new TimeOutException(); + } + + if (ply > 0 && (board.isRepetition(2) || board.getHalfMoveCounter() > 100 || board.isInsufficientMaterial())) + { + return DRAW_EVAL; + } + + if (ply > 0) + { + alpha = Math.max(alpha, -MATE_EVAL + ply); + beta = Math.min(beta, MATE_EVAL - ply - 1); + + if (alpha >= beta) + { + return alpha; + } + } + + if (depth <= 0 || ply >= MAX_PLY) + { + this.threadData.nodes.decrementAndGet(); + return quiesce(board, alpha, beta, ply); + } + + if (depth >= MAX_PLY) + { + depth = MAX_PLY - 1; + } + + TranspositionTable.Entry currentMoveEntry = sharedThreadData.tt.probe(board.getIncrementalHashKey()); + + sse.ttHit = currentMoveEntry.hit() && currentMoveEntry.verifySignature(board.getIncrementalHashKey()); + + if (!inSingularSearch && !isPV && sse.ttHit && currentMoveEntry.getDepth() >= depth) + { + eval = currentMoveEntry.getEvaluation(); + switch (currentMoveEntry.getNodeType()) + { + case TranspositionTable.NODETYPE_EXACT: + return eval; + case TranspositionTable.NODETYPE_UPPERBOUND: + if (eval <= alpha) + { + return eval; + } + break; + case TranspositionTable.NODETYPE_LOWERBOUND: + if (eval >= beta) + { + return eval; + } + break; + default: + sse.ttHit = false; // TT write race + } + } + + ttMove = sse.ttHit ? currentMoveEntry.getMove() : null; + ttCapture = ttMove != null && !board.isQuiet(ttMove); + ttPV = isPV | (currentMoveEntry.hit() && currentMoveEntry.wasPV()); + + if (inCheck) + { + eval = sse.staticEval = VALUE_NONE; + } + else + { + if (sse.ttHit) + { + eval = sse.staticEval = currentMoveEntry.getStaticEval(); + + if (currentMoveEntry.getEvaluation() != VALUE_NONE) + { + eval = currentMoveEntry.getEvaluation(); + switch (currentMoveEntry.getNodeType()) + { + case TranspositionTable.NODETYPE_EXACT: + break; + case TranspositionTable.NODETYPE_UPPERBOUND: + if (eval > sse.staticEval) + { + eval = sse.staticEval; + } + break; + case TranspositionTable.NODETYPE_LOWERBOUND: + if (eval < sse.staticEval) + { + eval = sse.staticEval; + } + break; + default: + sse.ttHit = false; // TT write race + } + } + } + else + { + eval = sse.staticEval = evaluate(board); + + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_NONE, TranspositionTable.DEPTH_NONE, VALUE_NONE, null, + sse.staticEval, ttPV); + } + } + + improving = false; + + if (!inCheck) + { + if (ss.get(ply - 2).staticEval != VALUE_NONE) + { + improving = ss.get(ply - 2).staticEval < sse.staticEval; + } + + else if (ss.get(ply - 4).staticEval != VALUE_NONE) + { + improving = ss.get(ply - 4).staticEval < sse.staticEval; + } + + else + { + improving = true; + } + } + + if (!inSingularSearch && !isPV && !inCheck && (ttMove == null || ttCapture) && depth < 7 && eval >= beta + && eval - depth * 70 + (improving ? 70 : 0) >= beta) + { + return beta > -MATE_IN_MAX_PLY ? beta + (eval - beta) / 3 : eval; + } + + if (!inSingularSearch && cutNode && ply > 0 && eval >= beta && beta < MATE_IN_MAX_PLY && !inCheck + && (ss.get(ply - 1).move == null || !ss.get(ply - 1).move.equals(Constants.emptyMove)) + && board.hasNonPawnMaterial()) + { + int r = depth / 3 + 4 + Math.min((eval - beta) / 200, 3); + + board.doNullMove(); + sse.move = Constants.emptyMove; + sse.continuationHistory = threadData.continuationHistories.get(board, sse.move); + int nullEval = -mainSearch(board, depth - r, -beta, -beta + 1, ply + 1, !cutNode); + board.undoMove(); + + if (nullEval >= beta && nullEval < MATE_IN_MAX_PLY) + { + if (this.nmpMinPly != 0 || depth < 12) + { + return nullEval; + } + + this.nmpMinPly = ply + 3 * (depth - r) / 4; + + int v = mainSearch(board, depth - r, -beta, -beta + 1, ply, false); + + this.nmpMinPly = 0; + + if (v >= beta) + { + return nullEval; + } + } + } + + if (!inCheck && depth <= 5 && eval + 256 * depth < alpha) + { + int razorValue = quiesce(board, alpha, alpha + 1, ply); + + if (razorValue <= alpha) + { + return razorValue; + } + } + + int oldAlpha = alpha; + + History[] currentContinuationHistories = new History[] { ss.get(ply - 1).continuationHistory, + ss.get(ply - 2).continuationHistory, null, ss.get(ply - 4).continuationHistory, null, + ss.get(ply - 6).continuationHistory }; + + List quietsSearched = new ArrayList<>(); + List capturesSearched = new ArrayList<>(); + + if (isPV && ttMove == null && threadData.rootDepth > 1 && depth > 5) + { + depth -= 2; + } + + MovePicker movePicker = new MovePicker(board, ttMove, sse.killer, threadData.history, threadData.captureHistory, + currentContinuationHistories); + + Move move; + + while ((move = movePicker.next()) != null) + { + if (move.equals(sse.excludedMove)) + { + continue; + } + + if (!board.isMoveLegal(move, false)) + { + continue; + } + + sse.moveCount++; + final boolean isQuiet = board.isQuiet(move); + final boolean givesCheck = board.attacksKing(move); + + int r = reduction[depth][sse.moveCount]; + int newdepth = depth - 1; + int lmrDepth = depth - r; + + if (isQuiet && !isPV && !givesCheck && sse.moveCount > 3 + depth * depth / (improving ? 1 : 2) + && alpha > -MATE_IN_MAX_PLY) + { + continue; + } + + if (bestValue > -MATE_IN_MAX_PLY && ply > 0 && board.hasNonPawnMaterial()) + { + if (!inCheck && !givesCheck && isQuiet && lmrDepth <= 8 + && sse.staticEval + lmrDepth * 150 + 150 <= alpha) + { + continue; + } + + if (depth < 9 && !board.staticExchangeEvaluation(move, + isQuiet && !givesCheck ? -65 * depth : -38 * depth * depth)) + { + continue; + } + } + + int extension = 0; + + if (!inSingularSearch && ply > 0 && sse.ttHit && move.equals(ttMove) && depth >= 4 + && Math.abs(currentMoveEntry.getEvaluation()) < MATE_IN_MAX_PLY + && (currentMoveEntry.getNodeType() == TranspositionTable.NODETYPE_EXACT + || currentMoveEntry.getNodeType() == TranspositionTable.NODETYPE_LOWERBOUND) + && currentMoveEntry.getDepth() > depth - 4) + { + int singularBeta = currentMoveEntry.getEvaluation() - 2 * depth; + int singularDepth = depth / 2; + int moveCountBackup = sse.moveCount; + + sse.excludedMove = move; + int singularValue = mainSearch(board, singularDepth, singularBeta - 1, singularBeta, ply, cutNode); + sse.excludedMove = null; + sse.moveCount = moveCountBackup; + + if (singularValue < singularBeta) + { + extension = 1; + + if (!isPV) + { + extension = 2; + } + } + + else if (singularValue >= beta) + { + return singularValue; + } + + } + + newdepth += extension; + + if (isQuiet) + { + final int history = threadData.history.get(board, move) * 2 + + currentContinuationHistories[0].get(board, move) + + currentContinuationHistories[1].get(board, move) + + currentContinuationHistories[3].get(board, move) + 6628; + + r -= history / 10000; + } + + else + { + final int history = threadData.captureHistory.get(board, move) - 6284; + + r -= history / 9000; + } + + AccumulatorDiff diff = board.doMove(move); + accumulators.push(board, move, diff); + sse.move = move; + sse.continuationHistory = threadData.continuationHistories.get(board, sse.move); + + int thisMoveEval = MIN_EVAL; + + if (sse.moveCount > 1 + (ply == 0 ? 1 : 0) && depth > 2) + { + r -= isPV ? 1 : 0; + r -= (ttPV && depth >= 6) ? 1 : 0; + r -= givesCheck ? 1 : 0; + r -= !isQuiet ? 1 : 0; + r += cutNode ? 1 : 0; + + int d = Math.min(newdepth, newdepth - r); + + thisMoveEval = -mainSearch(board, d, -(alpha + 1), -alpha, ply + 1, true); + + if (thisMoveEval > alpha) + { + thisMoveEval = -mainSearch(board, newdepth, -(alpha + 1), -alpha, ply + 1, !cutNode); + } + } + + else if (!isPV || sse.moveCount > 1) + { + thisMoveEval = -mainSearch(board, newdepth, -(alpha + 1), -alpha, ply + 1, !cutNode); + } + + if (isPV && (sse.moveCount == 1 || thisMoveEval > alpha)) + { + thisMoveEval = -mainSearch(board, newdepth, -beta, -alpha, ply + 1, false); + } + + board.undoMove(); + accumulators.pop(); + + if (thisMoveEval > bestValue) + { + bestValue = thisMoveEval; + bestMove = move; + + if (isPV) + updatePV(move, ply); + } + + if (thisMoveEval > alpha) + { + alpha = thisMoveEval; + + if (ply == 0) + this.bestMove = move; + + if (alpha >= beta) + { + if (isQuiet) + { + sse.killer = move; + + threadData.history.register(board, move, stat_bonus(depth)); + + for (Move quietMove : quietsSearched) + { + threadData.history.register(board, quietMove, stat_malus(depth)); + } + + updateContinuationHistories(ply, depth, board, move, quietsSearched); + } + else + { + threadData.captureHistory.register(board, move, stat_bonus(depth)); + + for (Move capture : capturesSearched) + { + threadData.captureHistory.register(board, capture, stat_malus(depth)); + } + } + + break; + } + } + + if (isQuiet) + { + quietsSearched.add(move); + } + else + { + capturesSearched.add(move); + } + } + + if (sse.moveCount == 0) + { + if (inSingularSearch) + { + return alpha; + } + + if (inCheck) + { + return -MATE_EVAL + ply; + } + + return DRAW_EVAL; + } + + if (!inSingularSearch) + { + if (alpha >= beta) + { + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_LOWERBOUND, depth, bestValue, bestMove, sse.staticEval, ttPV); + } + + else if (alpha == oldAlpha) + { + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_UPPERBOUND, depth, bestValue, ttMove, sse.staticEval, ttPV); + } + + else if (alpha > oldAlpha) + { + sharedThreadData.tt.write(currentMoveEntry, board.getIncrementalHashKey(), + TranspositionTable.NODETYPE_EXACT, depth, bestValue, bestMove, sse.staticEval, ttPV); + } + } + + return bestValue; + } + + public void iterativeDeepening(boolean suppressOutput) + { + int currentScore; + int alpha, beta; + int delta; + + currentScore = MIN_EVAL; + Move[] lastCompletePV = null; + alpha = MIN_EVAL; + beta = MAX_EVAL; + delta = VALUE_NONE; + + try + { + for (int i = 1; i < MAX_PLY; i++) + { + if (this.threadData.id == 0 && (i > this.threadData.mainThreadData.limits.getDepth() + || this.timeManager.shouldStopIterativeDeepening())) + { + break; + } + + threadData.rootDepth = i; + threadData.selDepth = 0; + this.bestMove = null; + + if (i > 3) + { + delta = 25; + alpha = Math.max(currentScore - delta, MIN_EVAL); + beta = Math.min(currentScore + delta, MAX_EVAL); + } + + while (true) + { + int newScore = mainSearch(this.internalBoard, i, alpha, beta, 0, false); + + if (newScore > alpha && newScore < beta) + { + currentScore = newScore; + lastCompletePV = threadData.pv[0].clone(); + + if (!suppressOutput && threadData.id == 0) + { + long totalNodes = 0; + + for (AlphaBeta thread : this.threadData.mainThreadData.threads) + { + totalNodes += thread.getNodesCount(); + } + + SearchReport report = new SearchReport(i, threadData.selDepth, totalNodes, + sharedThreadData.tt.hashfull(), currentScore, this.timeManager.timePassed(), + this.internalBoard, lastCompletePV); + + for (ISearchListener listener : threadData.mainThreadData.listeners) + { + listener.notify(report); + } + } + + break; + } + + else if (newScore <= alpha) + { + beta = (alpha + beta) / 2; + alpha = Math.max(alpha - delta, MIN_EVAL); + } + + else + { + beta = Math.min(beta + delta, MAX_EVAL); + } + + delta += delta * 3; + } + } + } + + catch (TimeOutException e) + { + } + + if (threadData.id == 0) + { + sharedThreadData.stopped.set(true); + } + + if (!suppressOutput && threadData.id == 0) + { + Move reportedBestMove = this.bestMove; + + if (reportedBestMove == null) + { + if (lastCompletePV == null) + { + reportedBestMove = getEmergencyBestMove(); + } + + else + { + reportedBestMove = lastCompletePV[0]; + } + } + + FinalReport report = new FinalReport(reportedBestMove); + + for (ISearchListener listener : threadData.mainThreadData.listeners) + { + listener.notify(report); + } + } + } + + private Move getEmergencyBestMove() + { + return this.internalBoard.legalMoves().get(0); + } + + public long getNodesCount() + { + return this.threadData.nodes.get(); + } + + public void reset() + { + this.ss = new SearchStack(MAX_PLY); + + this.threadData.nodes.set(0); + this.threadData.rootDepth = 0; + this.threadData.selDepth = 0; + this.threadData.history.fill(0); + this.threadData.captureHistory.fill(0); + this.threadData.continuationHistories.fill(0); + this.threadData.pv = new Move[MAX_PLY + 1][MAX_PLY + 1]; + + for (int i = 0; i < reduction.length; i++) + { + for (int j = 0; j < reduction[0].length; j++) + { + reduction[i][j] = (int) (1.60 + Math.log(i) * Math.log(j) / 2.17); + } + } + } + + public void setBoard(Board board) + { + this.internalBoard = board.clone(); + } + + public void updateTM(Limits limits) + { + this.threadData.mainThreadData.limits = limits.clone(); + this.timeManager.set(limits); + } + + @Override + public void run() + { + while (true) + { + try + { + this.sharedThreadData.endBarrier.await(); + this.sharedThreadData.startBarrier.await(); + } + + catch (InterruptedException | BrokenBarrierException e) + { + break; + } + + prepareThreadAndDoIterativeDeepening(); + } + } + + public void prepareThreadAndDoIterativeDeepening() + { + this.nmpMinPly = 0; + this.threadData.nodes.set(0); + this.ss = new SearchStack(MAX_PLY); + this.sharedThreadData.stopped.set(false); + this.accumulators = new AccumulatorStack(sharedThreadData.network); + this.accumulators.init(this.internalBoard); + this.bestMove = null; + clearPV(); + + iterativeDeepening(false); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/AveragedEntry.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/AveragedEntry.java new file mode 100644 index 0000000..8c4c26e --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/AveragedEntry.java @@ -0,0 +1,43 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Debug; + +public class AveragedEntry implements DebugEntry +{ + long total; + long count; + + public AveragedEntry() + { + total = 0; + count = 0; + } + + public void add(long number) + { + count++; + total += number; + } + + public String toString() + { + return "Mean: " + total / count + " Hits: " + count; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/DebugEntry.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/DebugEntry.java new file mode 100644 index 0000000..716b0b8 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/DebugEntry.java @@ -0,0 +1,25 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Debug; + +public interface DebugEntry +{ + +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/Debugger.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/Debugger.java new file mode 100644 index 0000000..9d93751 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/Debugger.java @@ -0,0 +1,61 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Debug; + +import java.util.*; + +public class Debugger +{ + private static Map averages = new HashMap<>(); + private static Map counters = new HashMap<>(); + + public static void dbg_mean_of(String name, long value) + { + if (!averages.containsKey(name)) + { + averages.put(name, new AveragedEntry()); + } + + averages.get(name).add(value); + } + + public static void dbg_hit_on(String name, boolean hit) + { + if (!counters.containsKey(name)) + { + counters.put(name, new FrequencyEntry()); + } + + counters.get(name).add(hit); + } + + public static void print() + { + for (Map.Entry entry : averages.entrySet()) + { + System.out.printf("Average of <%s>\t | %s\n", entry.getKey(), entry.getValue()); + } + + for (Map.Entry entry : counters.entrySet()) + { + System.out.printf("Hits of <%s>\t | %s\n", entry.getKey(), entry.getValue()); + } + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/FrequencyEntry.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/FrequencyEntry.java new file mode 100644 index 0000000..3b45e48 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Debug/FrequencyEntry.java @@ -0,0 +1,47 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Debug; + +public class FrequencyEntry implements DebugEntry +{ + long count; + long hit; + + public FrequencyEntry() + { + count = 0; + hit = 0; + } + + public void add(boolean hit) + { + count++; + + if (hit) + { + this.hit++; + } + } + + public String toString() + { + return "Hits: " + count + " Frequency: " + String.format("%.02f", 100d * hit / count) + "%"; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/CaptureHistory.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/CaptureHistory.java new file mode 100644 index 0000000..a1e8605 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/CaptureHistory.java @@ -0,0 +1,104 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.History; + +import java.util.Arrays; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class CaptureHistory implements History +{ + private final int[][][] history; + + static final int MAX_BONUS = 16384; + + public CaptureHistory() + { + history = new int[Piece.values().length][Square.values().length][PieceType.values().length]; + } + + public int get(Piece piece, Square to, PieceType captured) + { + return history[piece.ordinal()][to.ordinal()][captured.ordinal()]; + } + + private static int clamp(int v) + { + return v >= CaptureHistory.MAX_BONUS ? CaptureHistory.MAX_BONUS : (Math.max(v, -16384)); + } + + public void register(Piece piece, Square to, PieceType captured, int value) + { + int clampedValue = clamp(value); + + if (captured == null) + { + captured = PieceType.NONE; + } + + history[piece.ordinal()][to.ordinal()][captured.ordinal()] += clampedValue + - history[piece.ordinal()][to.ordinal()][captured.ordinal()] * Math.abs(clampedValue) / MAX_BONUS; + } + + @Override + public int get(Board board, Move move) + { + Piece movedPiece = board.getPiece(move.getFrom()); + + if (move.getTo().equals(board.getEnPassant()) && movedPiece.getPieceType().equals(PieceType.PAWN)) + { + return get(movedPiece, board.getEnPassant(), PieceType.PAWN); + } + + if (Piece.NONE.equals(board.getPiece(move.getTo()))) + { + return get(movedPiece, move.getTo(), PieceType.NONE); + } + + return get(movedPiece, move.getTo(), board.getPiece(move.getTo()).getPieceType()); + } + + @Override + public void register(Board board, Move move, int value) + { + Piece movedPiece = board.getPiece(move.getFrom()); + + if (move.getTo().equals(board.getEnPassant()) && movedPiece.getPieceType().equals(PieceType.PAWN)) + { + register(movedPiece, board.getEnPassant(), PieceType.PAWN, value); + return; + } + + register(movedPiece, move.getTo(), board.getPiece(move.getTo()).getPieceType(), value); + } + + @Override + public void fill(int x) + { + for (int[][] x1 : history) + { + for (int[] x2 : x1) + { + Arrays.fill(x2, x); + } + } + } +} \ No newline at end of file diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/ContinuationHistories.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/ContinuationHistories.java new file mode 100644 index 0000000..62c79f6 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/ContinuationHistories.java @@ -0,0 +1,63 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.History; + +import java.util.Arrays; + +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.Piece; +import org.shawn.games.Serendipity.Chess.Square; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class ContinuationHistories +{ + private final PieceToHistory[][] continuationHistories; + + public ContinuationHistories() + { + continuationHistories = new PieceToHistory[Piece.values().length][Square.values().length]; + + for (int i = 0; i < Piece.values().length; i++) + { + for (int j = 0; j < Square.values().length; j++) + { + continuationHistories[i][j] = new PieceToHistory(); + } + } + } + + public History get(Piece piece, Square to) + { + return continuationHistories[piece.ordinal()][to.ordinal()]; + } + + public History get(Board board, Move move) + { + return get(board.getPiece(move.getFrom()), move.getTo()); + } + + public void fill(int x) + { + for (PieceToHistory[] row : continuationHistories) + { + Arrays.stream(row).forEach(history -> history.fill(x)); + } + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/FromToHistory.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/FromToHistory.java new file mode 100644 index 0000000..1581f1d --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/FromToHistory.java @@ -0,0 +1,80 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.History; + +import java.util.Arrays; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class FromToHistory implements History +{ + private final int[] history; + + static final int MAX_BONUS = 16384; + + final int DIMENSION = Square.values().length; + + public FromToHistory() + { + history = new int[DIMENSION * DIMENSION]; + } + + public int get(Square from, Square to) + { + return history[from.ordinal() * DIMENSION + to.ordinal()]; + } + + public int get(Move move) + { + return get(move.getFrom(), move.getTo()); + } + + private static int clamp(int v) + { + return v >= FromToHistory.MAX_BONUS ? FromToHistory.MAX_BONUS : (Math.max(v, -16384)); + } + + public void register(Square from, Square to, int value) + { + int clampedValue = clamp(value); + + history[from.ordinal() * DIMENSION + to.ordinal()] += clampedValue + - history[from.ordinal() * DIMENSION + to.ordinal()] * Math.abs(clampedValue) / MAX_BONUS; + } + + @Override + public int get(Board board, Move move) + { + return get(move.getFrom(), move.getTo()); + } + + @Override + public void register(Board board, Move move, int value) + { + register(move.getFrom(), move.getTo(), value); + } + + @Override + public void fill(int x) + { + Arrays.fill(history, x); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/History.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/History.java new file mode 100644 index 0000000..7752402 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/History.java @@ -0,0 +1,32 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.History; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.*; + +public interface History +{ + int get(Board board, Move move); + + void register(Board board, Move move, int value); + + void fill(int x); +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/PieceToHistory.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/PieceToHistory.java new file mode 100644 index 0000000..e969e75 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/History/PieceToHistory.java @@ -0,0 +1,81 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.History; + +import java.util.Arrays; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class PieceToHistory implements History +{ + private final int[][] history; + + static final int MAX_BONUS = 16384; + + public PieceToHistory() + { + history = new int[Piece.values().length][Square.values().length]; + } + + public int get(Piece piece, Square to) + { + return history[piece.ordinal()][to.ordinal()]; + } + + public int get(Piece piece, Move move) + { + return get(piece, move.getTo()); + } + + private static int clamp(int v) + { + return v >= PieceToHistory.MAX_BONUS ? PieceToHistory.MAX_BONUS : (Math.max(v, -16384)); + } + + public void register(Piece piece, Square to, int value) + { + int clampedValue = clamp(value); + + history[piece.ordinal()][to.ordinal()] += clampedValue + - history[piece.ordinal()][to.ordinal()] * Math.abs(clampedValue) / MAX_BONUS; + } + + @Override + public int get(Board board, Move move) + { + return get(board.getPiece(move.getFrom()), move.getTo()); + } + + @Override + public void register(Board board, Move move, int value) + { + register(board.getPiece(move.getFrom()), move.getTo(), value); + } + + @Override + public void fill(int x) + { + for (int[] row : history) + { + Arrays.fill(row, x); + } + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Limits.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Limits.java new file mode 100644 index 0000000..32db635 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Limits.java @@ -0,0 +1,99 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +public class Limits +{ + private long time; + private long increment; + private int movesToGo; + + private long nodes; + private int depth; + + public Limits() + { + this(100, 0, 0, -1, 256); + } + + public Limits(long time, long increment, int movesToGo, long nodes, int depth) + { + this.time = time; + this.increment = increment; + this.movesToGo = movesToGo; + this.nodes = nodes; + this.depth = depth; + } + + public long getTime() + { + return time; + } + + public void setTime(long time) + { + this.time = time; + } + + public long getIncrement() + { + return increment; + } + + public void setIncrement(long increment) + { + this.increment = increment; + } + + public int getMovesToGo() + { + return movesToGo; + } + + public void setMovesToGo(int movesToGo) + { + this.movesToGo = movesToGo; + } + + public long getNodes() + { + return nodes; + } + + public void setNodes(long nodes) + { + this.nodes = nodes; + } + + public int getDepth() + { + return depth; + } + + public void setDepth(int depth) + { + this.depth = depth; + } + + public Limits clone() + { + return new Limits(time, increment, movesToGo, nodes, depth); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/FinalReport.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/FinalReport.java new file mode 100644 index 0000000..769dbef --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/FinalReport.java @@ -0,0 +1,32 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Listener; + +import org.shawn.games.Serendipity.Chess.move.Move; + +public class FinalReport +{ + public final Move bestMove; + + public FinalReport(Move bestMove) + { + this.bestMove = bestMove; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/ISearchListener.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/ISearchListener.java new file mode 100644 index 0000000..8fb36fe --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/ISearchListener.java @@ -0,0 +1,27 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Listener; + +public interface ISearchListener +{ + public void notify(SearchReport report); + + public void notify(FinalReport report); +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/SearchReport.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/SearchReport.java new file mode 100644 index 0000000..e05e754 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/Listener/SearchReport.java @@ -0,0 +1,47 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search.Listener; + +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class SearchReport +{ + public final int depth; + public final int selDepth; + public final long nodes; + public final int hashfull; + public final int score; + public final long ms; + public final Board board; + public final Move[] pv; + + public SearchReport(int depth, int selDepth, long nodes, int hashfull, int score, long ms, Board board, Move[] pv) + { + this.depth = depth; + this.selDepth = selDepth; + this.nodes = nodes; + this.hashfull = hashfull; + this.score = score; + this.ms = ms; + this.board = board; + this.pv = pv; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/MovePicker.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/MovePicker.java new file mode 100644 index 0000000..b91c477 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/MovePicker.java @@ -0,0 +1,247 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import java.util.ArrayList; +import java.util.Collections; + +import org.shawn.games.Serendipity.Search.History.History; + +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.Piece; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class MovePicker +{ + private Board board; + private Move ttMove; + + private Move killer; + private History history; + private History captureHistory; + private History[] continuationHistories; + + private ArrayList moves; + + private int stage; + private int moveIndex; + + private static final int STAGE_NORMAL_TT = 0; + private static final int STAGE_NORMAL = 1; + private static final int STAGE_QSEARCH_TT = 2; + private static final int STAGE_QSEARCH_CAPTURE = 3; + + private static final int[] promoValue = { -2000000001, 2000000000, -2000000001, -2000000001, 2000000001 }; + + public MovePicker(Board board, Move ttMove) + { + this(board, ttMove, null, null, null, null); + } + + public MovePicker(Board board, Move ttMove, Move killer, History history, History captureHistory, + History[] continuationHistories) + { + this.board = board; + this.ttMove = ttMove; + + if (ttMove == null || !board.isMovePseudoLegal(ttMove)) + { + this.ttMove = null; + this.stage = STAGE_NORMAL; + } + else + { + this.stage = STAGE_NORMAL_TT; + } + + this.killer = killer; + this.history = history; + this.captureHistory = captureHistory; + this.continuationHistories = continuationHistories; + } + + public MovePicker(Board board, Move ttMove, History captureHistory) + { + this.board = board; + this.ttMove = ttMove; + + if (ttMove == null || !board.isMovePseudoLegal(ttMove) || !board.isCapture(ttMove)) + { + this.ttMove = null; + this.stage = STAGE_QSEARCH_CAPTURE; + } + + else + { + this.stage = STAGE_QSEARCH_TT; + } + + this.killer = null; + this.history = null; + this.captureHistory = captureHistory; + this.continuationHistories = null; + } + + private static int pieceValue(Piece p) + { + if (p.getPieceType() == null) + { + return 0; + } + + return p.getPieceType().ordinal() + 1; + } + + private int captureValue(Move move) + { + return pieceValue(board.getPiece(move.getTo())) * 100 + captureHistory.get(board, move) / 256; + } + + private int scoreMove(Move move) + { + if (!move.getPromotion().equals(Piece.NONE)) + { + return promoValue[move.getPromotion().getPieceType().ordinal()]; + } + + if (!board.isQuiet(move)) + { + int score = board.staticExchangeEvaluation(move, -20) ? 900000000 : -1000000; + score += captureValue(move); + return score; + } + + if (move.equals(killer)) + { + return 800000000; + } + + int moveValue = history.get(board, move); + + moveValue += continuationHistories[0].get(board, move); + moveValue += continuationHistories[1].get(board, move); + moveValue += continuationHistories[3].get(board, move); + moveValue += continuationHistories[5].get(board, move) / 2; + + return moveValue; + } + + public void initMoves() + { + this.moves = new ArrayList(); + board.generatePseudoLegalMoves(moves); + + for (int i = 0; i < this.moves.size(); i++) + { + Move currentMove = this.moves.get(i); + currentMove.setScore(scoreMove(currentMove)); + } + } + + public void initCaptures() + { + this.moves = new ArrayList(); + board.generatePseudoLegalCaptures(moves); + + for (int i = 0; i < this.moves.size(); i++) + { + Move currentMove = this.moves.get(i); + currentMove.setScore(captureValue(currentMove)); + } + } + + public Move selectMove() + { + if (this.moveIndex >= this.moves.size()) + { + return null; + } + + int swapIndex = this.moveIndex; + int maxScore = this.moves.get(this.moveIndex).getScore(); + + for (int i = this.moveIndex + 1; i < this.moves.size(); i++) + { + int currScore = this.moves.get(i).getScore(); + + if (maxScore < currScore) + { + swapIndex = i; + maxScore = currScore; + } + } + + Collections.swap(moves, swapIndex, this.moveIndex); + + this.moveIndex++; + + return moves.get(this.moveIndex - 1); + } + + public Move next() + { + switch (stage) + { + case STAGE_NORMAL_TT: + stage++; + return this.ttMove; + + case STAGE_NORMAL: + if (this.moves == null) + { + initMoves(); + } + + { + Move ret = selectMove(); + + if (ret != null && ret.equals(ttMove)) + { + ret = selectMove(); + } + + return ret; + } + + case STAGE_QSEARCH_TT: + stage++; + return this.ttMove; + + case STAGE_QSEARCH_CAPTURE: + if (this.moves == null) + { + initCaptures(); + } + + { + Move ret = selectMove(); + + if (ret != null && ret.equals(ttMove)) + { + ret = selectMove(); + } + + return ret; + } + } + + return null; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SearchStack.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SearchStack.java new file mode 100644 index 0000000..51ec9f2 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SearchStack.java @@ -0,0 +1,67 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import org.shawn.games.Serendipity.Search.History.History; +import org.shawn.games.Serendipity.Search.History.PieceToHistory; + +import org.shawn.games.Serendipity.Chess.move.Move; + +public class SearchStack +{ + public static class SearchState + { + public boolean inCheck; + public boolean ttHit; + public int moveCount; + public int staticEval; + public Move killer; + public Move move; + public Move excludedMove; + public History continuationHistory; + + public SearchState() + { + this.staticEval = AlphaBeta.VALUE_NONE; + } + } + + private final SearchState[] stack; + + public SearchStack(int n) + { + stack = new SearchState[n + 9]; + + for (int i = 0; i < stack.length; i++) + { + stack[i] = new SearchState(); + } + + for (int i = 0; i < 6; i++) + { + stack[i].continuationHistory = new PieceToHistory(); + } + } + + public SearchState get(int index) + { + return stack[index + 6]; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SharedThreadData.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SharedThreadData.java new file mode 100644 index 0000000..4edc7d4 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/SharedThreadData.java @@ -0,0 +1,44 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.shawn.games.Serendipity.NNUE.NNUE; + +public class SharedThreadData +{ + final NNUE network; + final AtomicBoolean stopped; + final TranspositionTable tt; + final CyclicBarrier endBarrier; + final CyclicBarrier startBarrier; + + public SharedThreadData(TranspositionTable tt, CyclicBarrier startBarrier, CyclicBarrier endBarrier, NNUE network, + AtomicBoolean stopped) + { + this.tt = tt; + this.network = network; + this.stopped = stopped; + this.endBarrier = endBarrier; + this.startBarrier = startBarrier; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadData.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadData.java new file mode 100644 index 0000000..7e6d617 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadData.java @@ -0,0 +1,79 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import org.shawn.games.Serendipity.Search.History.CaptureHistory; +import org.shawn.games.Serendipity.Search.History.ContinuationHistories; +import org.shawn.games.Serendipity.Search.History.FromToHistory; +import org.shawn.games.Serendipity.Search.History.History; +import org.shawn.games.Serendipity.Search.Listener.ISearchListener; + +import org.shawn.games.Serendipity.Chess.move.Move; + +public class ThreadData +{ + final History history; + final History captureHistory; + final ContinuationHistories continuationHistories; + final MainThreadData mainThreadData; + Move[][] pv; + + int rootDepth; + int selDepth; + final int id; + AtomicLong nodes; + + public static class MainThreadData + { + final List listeners; + final List threads; + Limits limits; + + public MainThreadData(Limits limits, List listeners, List threads) + { + this.limits = limits; + this.listeners = listeners; + this.threads = threads; + } + } + + public ThreadData(int id, MainThreadData mainThreadData) + { + this.id = id; + + this.history = new FromToHistory(); + this.captureHistory = new CaptureHistory(); + this.continuationHistories = new ContinuationHistories(); + + this.rootDepth = 0; + this.selDepth = 0; + this.pv = new Move[AlphaBeta.MAX_PLY + 1][AlphaBeta.MAX_PLY + 1]; + this.mainThreadData = mainThreadData; + this.nodes = new AtomicLong(0); + } + + public ThreadData(int id) + { + this(id, null); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadManager.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadManager.java new file mode 100644 index 0000000..a627b94 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/ThreadManager.java @@ -0,0 +1,172 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.shawn.games.Serendipity.NNUE.NNUE; +import org.shawn.games.Serendipity.Search.Listener.ISearchListener; +import org.shawn.games.Serendipity.UCI.UCIListener; + +import org.shawn.games.Serendipity.Chess.Board; + +public class ThreadManager +{ + List threadData; + List threads; + int threadsCount; + + CyclicBarrier startBarrier; + CyclicBarrier endBarrier; + ExecutorService pool; + + AtomicBoolean stopped; + + TranspositionTable tt; + NNUE network; + + public void reinit(int threadsCount) + { + init(threadsCount, tt, network); + } + + public void reinit(NNUE network) + { + init(threadsCount, tt, network); + } + + public void init(int threadsCount, TranspositionTable tt, NNUE network) + { + if (this.threads != null) + { + this.shutdownAll(); + } + + this.threadsCount = threadsCount; + this.startBarrier = new CyclicBarrier(this.threadsCount + 1); + this.endBarrier = new CyclicBarrier(this.threadsCount + 1); + this.threadData = new ArrayList<>(); + this.threads = new ArrayList<>(); + + this.tt = tt; + this.network = network; + + pool = Executors.newFixedThreadPool(this.threadsCount); + + this.stopped = new AtomicBoolean(false); + final ArrayList listeners = new ArrayList<>(); + + startBarrier = new CyclicBarrier(this.threadsCount + 1); + endBarrier = new CyclicBarrier(this.threadsCount + 1); + + final SharedThreadData sharedData = new SharedThreadData(tt, startBarrier, endBarrier, network, this.stopped); + final ThreadData.MainThreadData mainThreadData = new ThreadData.MainThreadData(null, listeners, threads); + + threadData.add(new ThreadData(0, mainThreadData)); + + for (int i = 1; i < threadsCount; i++) + { + threadData.add(new ThreadData(i)); + } + + listeners.add(new UCIListener()); + + for (int i = 0; i < this.threadsCount; i++) + { + threads.add(new AlphaBeta(sharedData, threadData.get(i))); + pool.execute(threads.get(i)); + } + } + + public void initThreads(Board board, Limits limits) + { + for (AlphaBeta thread : threads) + { + thread.setBoard(board); + } + + threads.get(0).updateTM(limits); + } + + public void nextMove(Board board, Limits limits) + { + try + { + this.endBarrier.await(); + } + catch (InterruptedException | BrokenBarrierException e) + { + e.printStackTrace(); + return; + } + + initThreads(board, limits); + + try + { + this.startBarrier.await(); + } + catch (InterruptedException | BrokenBarrierException e) + { + e.printStackTrace(); + } + } + + public void clearData() + { + for (AlphaBeta thread : threads) + { + thread.reset(); + } + } + + public long getNodes() + { + long nodes = 0; + + for (AlphaBeta thread : threads) + { + nodes += thread.getNodesCount(); + } + + return nodes; + } + + public AlphaBeta getMainThread() + { + return threads.get(0); + } + + public void shutdownAll() + { + pool.shutdownNow(); + } + + public void stop() + { + this.stopped.set(true); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeManager.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeManager.java new file mode 100644 index 0000000..8139bb4 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeManager.java @@ -0,0 +1,96 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import org.shawn.games.Serendipity.UCI.IntegerOption; + +public class TimeManager +{ + + private long startTime; + private long hardLimitTimeStamp; + private long softLimitTimeStamp; + + private static final IntegerOption moveOverHead = new IntegerOption(100, 0, 30000, "Move_Overhead"); + + public void set(Limits limits) + { + set(limits.getTime(), limits.getIncrement(), limits.getMovesToGo()); + } + + public void set(long timeLeft, long increment, int movesToGo) + { + if (timeLeft < 0) + { + timeLeft = 1000; + } + + timeLeft -= Math.min(moveOverHead.get(), timeLeft) / 2; + long hardLimit; + long softLimit; + + if (movesToGo != 0 && movesToGo != -1) + { + hardLimit = timeLeft / movesToGo + increment * 3 / 4; + softLimit = hardLimit / 2; + + this.startTime = System.nanoTime(); + this.hardLimitTimeStamp = startTime + 1000000L * hardLimit; + this.softLimitTimeStamp = startTime + 1000000L * softLimit; + + return; + } + + else if (movesToGo == -1) + { + hardLimit = softLimit = timeLeft; + + this.startTime = System.nanoTime(); + this.hardLimitTimeStamp = this.softLimitTimeStamp = startTime + 1000000L * timeLeft; + + return; + } + + int baseTime = (int) (timeLeft * 0.054 + increment * 0.85); + int maxTime = (int) (timeLeft * 0.76); + + hardLimit = Math.min(maxTime, (int) (baseTime * 3.04)); + softLimit = Math.min(maxTime, (int) (baseTime * 0.76)); + + this.startTime = System.nanoTime(); + this.hardLimitTimeStamp = startTime + 1000000L * hardLimit; + this.softLimitTimeStamp = startTime + 1000000L * softLimit; + } + + public boolean shouldStop() + { + return System.nanoTime() > this.hardLimitTimeStamp; + } + + public boolean shouldStopIterativeDeepening() + { + return System.nanoTime() > this.softLimitTimeStamp; + } + + public long timePassed() + { + return (System.nanoTime() - this.startTime) / 1000000; + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeOutException.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeOutException.java new file mode 100644 index 0000000..6fb7250 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TimeOutException.java @@ -0,0 +1,25 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +public class TimeOutException extends Exception +{ + private static final long serialVersionUID = 584382830128540437L; +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TranspositionTable.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TranspositionTable.java new file mode 100644 index 0000000..3c6cb37 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/Search/TranspositionTable.java @@ -0,0 +1,220 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.Search; + +import java.util.Arrays; + +import org.shawn.games.Serendipity.Chess.Square; +import org.shawn.games.Serendipity.Chess.move.*; + +public class TranspositionTable +{ + public static final int NODETYPE_NONE = 0b00; + public static final int NODETYPE_LOWERBOUND = 0b01; + public static final int NODETYPE_UPPERBOUND = 0b10; + public static final int NODETYPE_EXACT = 0b11; + + private static final int DEPTH_OFFSET = -4; + public static final int DEPTH_NONE = -3; + public static final int DEPTH_QS = -1; + + public class Entry + { + private final int signature; + private final int depth; + private final int type; + private final int evaluation; + private final int staticEval; + private final Move move; + private final boolean ttPV; + private final boolean hit; + + public Entry(short fragment1, long fragment2) + { + this(fragment1 & 0b11, (fragment1 >>> 8) + DEPTH_OFFSET, (int) (fragment2 & 0xFFFF), + (int) ((fragment2 & 0xFFF0000) >> 16), (short) ((fragment2 & 0xFFFF0000000L) >> 28), + (int) (fragment2 >> 44), (fragment1 & 0b100) != 0, (fragment1 != 0) && (fragment2 != 0)); + } + + public Entry(int nodeType, int depth, int signature, int move, int staticEval, int evaluation, boolean ttPV, + boolean hit) + { + this.signature = signature; + this.depth = depth; + this.type = nodeType; + this.move = move == 0 ? null : new Move(Square.squareAt(move >> 6), Square.squareAt(move & 0b111111)); + this.evaluation = evaluation; + this.staticEval = staticEval; + this.ttPV = ttPV; + this.hit = hit; + } + + public long getSignature() + { + return signature; + } + + public boolean verifySignature(long signature) + { + return (int) (signature >>> 48) == this.signature; + } + + public int getDepth() + { + return this.depth; + } + + public int getNodeType() + { + return this.type; + } + + public int getEvaluation() + { + return evaluation; + } + + public int getStaticEval() + { + return staticEval; + } + + public Move getMove() + { + return move; + } + + public boolean wasPV() + { + return ttPV; + } + + public boolean hit() + { + return hit; + } + } + + private int size; + private int mask; + + // depth: (0-255) 8 bits + // unused: 5 bits + // ttPV: 1 bit + // nodeType: 2 bits + + private short[] data1; + + // evaluation: 16 bits + // staticEval: 16 bits + // move: 12 bits + // square: 6 bits + // square: 6 bits + // signature: 16 bits + + private long[] data2; + + private static final int ENTRY_SIZE = 10; + + public TranspositionTable(int size) + { + size *= 1048576 / ENTRY_SIZE; + + this.size = Integer.highestOneBit(size); + this.mask = this.size - 1; + this.data1 = new short[this.size]; + this.data2 = new long[this.size]; + } + + public Entry probe(long hash) + { + final short fragment1 = data1[(int) (hash & mask)]; + final long fragment2 = data2[(int) (hash & mask)]; + + return new Entry(fragment1, fragment2); + } + + public void write(Entry entry, long hash, int nodeType, int depth, int evaluation, Move move, int staticEval, boolean ttPV) + { + if (entry == null || !entry.hit() || nodeType == NODETYPE_EXACT || !entry.verifySignature(hash) + || depth > entry.getDepth() - 4) + { + final int writtenDepth = depth - DEPTH_OFFSET; + final short fragment1 = (short) (nodeType | (ttPV ? 0b100 : 0b000) | (writtenDepth << 8)); + final long fragment2 = ((hash >>> 48) + | (((move == null) ? 0 : ((move.getFrom().ordinal() << 6) | move.getTo().ordinal())) << 16) + | ((staticEval & 0xFFFFL) << 28) | ((long) evaluation << 44)); + + data1[(int) hash & mask] = fragment1; + data2[(int) hash & mask] = fragment2; + } + } + + public void clear() + { + Arrays.fill(data1, (short) 0); + Arrays.fill(data2, 0); + } + + public void resize(int size) + { + size *= 1048576 / ENTRY_SIZE; + this.size = Integer.highestOneBit(size); + this.mask = this.size - 1; + this.data1 = new short[this.size]; + this.data2 = new long[this.size]; + } + + public int hashfull() + { + int hashfull = 0; + + for (int i = 0; i < 1000; i++) + { + if (this.data2[i] != 0) + { + hashfull++; + } + } + + return hashfull; + } + + public int hashfull_accurate() + { + int hashfull = 0; + int minimum_hash = 1048576 / ENTRY_SIZE; + + for (int i = 0; i < minimum_hash; i++) + { + if (this.data2[i] != 0) + { + hashfull++; + } + } + + return hashfull * 1000 / minimum_hash; + } + + public int getSize() + { + return this.size * ENTRY_SIZE / 1048576; + } +} \ No newline at end of file diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Bench.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Bench.java new file mode 100644 index 0000000..1374d17 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Bench.java @@ -0,0 +1,111 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +import org.shawn.games.Serendipity.Search.AlphaBeta; +import org.shawn.games.Serendipity.Search.Limits; +import org.shawn.games.Serendipity.Search.ThreadManager; +import org.shawn.games.Serendipity.Search.Debug.Debugger; + +import org.shawn.games.Serendipity.Chess.*; + +public class Bench +{ + static private final String[] benchPositions = new String[] { + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10", + "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11", + "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", + "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14 moves d4e6", + "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14 moves g2g4", + "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15", + "r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13", + "r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16", + "4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17", + "2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11", + "r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16", + "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22", + "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18", + "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22", + "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26", + "6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1", "3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1", + "2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1 moves g5g6 f3e3 g6g5 e3f3", + "8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1", "7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1", + "8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1", "8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1", + "8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1", "8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1", + "5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1", "6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1", + "1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1", + "6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1", "8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1", + "5rk1/q6p/2p3bR/1pPp1rP1/1P1Pp3/P3B1Q1/1K3P2/R7 w - - 93 90", + "4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21", + "r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16", + "3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40", + "4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1", + + // 5-man positions + "8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate + "8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", // Na2 - mate + "8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", // draw + + // 6-man positions + "8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", // Re5 - mate + "8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", // Ka2 - mate + "8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw + + // 7-man positions + "8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw + + // Mate and stalemate positions + "6k1/3b3r/1p1p4/p1n2p2/1PPNpP1q/P3Q1p1/1R1RB1P1/5K2 b - - 0 1", + "r2r1n2/pp2bk2/2p1p2p/3q4/3PN1QP/2P3R1/P4PP1/5RK1 w - - 0 1", "8/8/8/8/8/6k1/6p1/6K1 w - -", + "7k/7P/6K1/8/3B4/8/8/8 b - -", }; + + public static void bench(ThreadManager engine, int depth, boolean OBStandard) + { + long totalNodes = 0; + long startTime = System.nanoTime(); + Board board = new Board(); + AlphaBeta mainThread = engine.getMainThread(); + for (String fen : benchPositions) + { + board.loadFromFen(fen); + engine.initThreads(board, new Limits(Integer.MAX_VALUE, Integer.MAX_VALUE, 1, -1, depth)); + mainThread.prepareThreadAndDoIterativeDeepening(); + totalNodes += mainThread.getNodesCount(); + } + + long endTime = System.nanoTime(); + + if (!OBStandard) + { + System.out.printf("Total time (ms)\t: %d\nNodes searched\t: %d\nNodes/second\t: %d\n", + (endTime - startTime) / 1000000L, totalNodes, totalNodes * 1000000000L / (endTime - startTime)); + } + else + { + System.out.printf("%d nodes %d nps", totalNodes, totalNodes * 1000000000L / (endTime - startTime)); + } + + Debugger.print(); + + engine.clearData(); + + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/IntegerOption.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/IntegerOption.java new file mode 100644 index 0000000..bf361a4 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/IntegerOption.java @@ -0,0 +1,81 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +public class IntegerOption implements UCIOption +{ + int value; + final String name; + final int defaultValue; + final int lowerBound; + final int upperBound; + + public IntegerOption(int value, int lowerBound, int upperBound, String name) + { + if (lowerBound > upperBound) + { + throw new IllegalArgumentException("lowerBound must be less than or equal to upperBound"); + } + + this.value = this.defaultValue = value; + this.lowerBound = lowerBound; + this.upperBound = upperBound; + this.name = name; + + UCI.addOption(name, this); + } + + @Override + public void set(String value) + { + int intValue = Integer.parseInt(value); + if (intValue < this.lowerBound) + { + this.value = this.lowerBound; + } + + else if (intValue > this.upperBound) + { + this.value = this.upperBound; + } + + else + { + this.value = intValue; + } + } + + public int get() + { + return value; + } + + public String toString() + { + return "option name " + name + " type spin default " + defaultValue + " min " + lowerBound + " max " + + upperBound; + } + + @Override + public String getString() + { + return Integer.toString(this.value); + } +} \ No newline at end of file diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/StringOption.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/StringOption.java new file mode 100644 index 0000000..a681a0b --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/StringOption.java @@ -0,0 +1,57 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +public class StringOption implements UCIOption +{ + String value; + final String name; + final String defaultValue; + + public StringOption(String value, String name) + { + this.value = this.defaultValue = value; + this.name = name; + + UCI.addOption(name, this); + } + + @Override + public void set(String value) + { + this.value = value; + } + + public String get() + { + return value; + } + + public String toString() + { + return "option name " + name + " type string default " + defaultValue; + } + + @Override + public String getString() + { + return this.value; + } +} \ No newline at end of file diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Tunable.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Tunable.java new file mode 100644 index 0000000..4ee9a49 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/Tunable.java @@ -0,0 +1,29 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +public class Tunable extends IntegerOption +{ + public Tunable(int value, int lowerBound, int upperBound, double step, double lr, String name) + { + super(value, lowerBound, upperBound, name); + System.out.println(name + ", int, " + value + ", " + lowerBound + ", " + upperBound + ", " + step + ", " + lr); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCI.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCI.java new file mode 100644 index 0000000..5934a10 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCI.java @@ -0,0 +1,364 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +import java.io.IOException; +import java.util.*; + +import org.shawn.games.Serendipity.NNUE.AccumulatorStack; +import org.shawn.games.Serendipity.NNUE.NNUE; +import org.shawn.games.Serendipity.Search.Limits; +import org.shawn.games.Serendipity.Search.ThreadManager; +import org.shawn.games.Serendipity.Search.TranspositionTable; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.*; + +public class UCI +{ + private static Board internalBoard; + private static Map options; + private static ThreadManager engine; + private static TranspositionTable transpositionTable; + private static NNUE network; + + private static ThreadsOption threads; + private static HashOption hash; + + public static class NNUEOption extends StringOption + { + public NNUEOption(String value, String name) + { + super(value, name); + } + + @Override + public void set(String value) + { + try + { + network = new NNUE("/" + value); + } + + catch (IOException e) + { + System.out.print("Error Loading NNUE"); + return; + } + + engine.reinit(network); + super.set(value); + } + } + + public static class HashOption extends IntegerOption + { + private final TranspositionTable tt; + + public HashOption(int value, int lowerBound, int upperBound, TranspositionTable tt, String name) + { + super(value, lowerBound, upperBound, name); + this.tt = tt; + } + + @Override + public void set(String value) + { + super.set(value); + tt.resize(super.value); + } + } + + public static class ThreadsOption extends IntegerOption + { + public ThreadsOption(int value, int lowerBound, int upperBound, String name) + { + super(value, lowerBound, upperBound, name); + } + + @Override + public void set(String value) + { + super.set(value); + engine.reinit(super.value); + } + } + + public static void main(String[] args) + { + transpositionTable = new TranspositionTable(4); + options = new HashMap<>(); + StringOption networkName = new NNUEOption("embedded.nnue", "nnuefile"); + threads = new ThreadsOption(1, 1, 1048576, "Threads"); + hash = new HashOption(4, 1, 32768, transpositionTable, "Hash"); + + try + { + network = new NNUE("/" + networkName.get()); + } + + catch (IOException e) + { + System.out.print("Error Loading NNUE"); + return; + } + + internalBoard = new Board(); + + engine = new ThreadManager(); + engine.init(threads.get(), transpositionTable, network); + + if (args.length == 1 && args[0].equals("bench")) + { + Bench.bench(engine, 10, true); + engine.shutdownAll(); + return; + } + + UCIMainLoop(); + } + + public static void addOption(String name, UCIOption option) + { + options.put(name, option); + } + + public static IntegerOption getOption(String name) + { + return (IntegerOption) options.get(name); + } + + public static void setOption(String name, String value) + { + UCIOption myOption = options.get(name); + myOption.set(value); + } + + private static long perft(Board board, int depth, int ply, boolean root) + { + if (depth == 0) + { + return 1; + } + + long nodes = 0; + List moves = board.legalMoves(); + + for (Move move : moves) + { + board.doMove(move); + + if (root) + { + long thisMoveNodes; + thisMoveNodes = perft(board, depth - 1, ply + 1, false); + System.out.println(move + ":\t" + thisMoveNodes); + nodes += thisMoveNodes; + } + + else + { + nodes += perft(board, depth - 1, ply + 1, false); + } + + board.undoMove(); + } + + return nodes; + } + + public static void UCIMainLoop() + { + Scanner input = new Scanner(System.in); + int depth; + while (input.hasNextLine()) + { + String command = input.nextLine(); + String[] fullCommand = command.split(" "); + + switch (command.split(" ")[0]) + { + case "isready": + System.out.println("readyok"); + break; + case "uci": + System.out.println("id name Serendipity"); + System.out.println("id author Shawn Xu"); + for (UCIOption option : options.values()) + { + System.out.println(option); + } + System.out.println("uciok"); + break; + case "ucinewgame": + System.gc(); + internalBoard = new Board(); + transpositionTable.clear(); + engine.init(threads.get(), transpositionTable, network); + break; + case "quit": + input.close(); + engine.shutdownAll(); + return; + case "perft": + if (fullCommand.length >= 2) + { + depth = Integer.parseInt(fullCommand[1]); + } + else + { + depth = 4; + } + long timeBegin = System.nanoTime(); + long totalNodes = perft(internalBoard, depth, 0, true); + long timeEnd = System.nanoTime(); + System.out.println("\nNodes searched:\t\t" + totalNodes); + System.out.println("Time spent (ms):\t" + (timeEnd - timeBegin) / 1000000); + System.out.println( + "Nodes per second:\t" + totalNodes * 1000 / Math.max((timeEnd - timeBegin) / 1000000, 1)); + break; + case "eval": + AccumulatorStack acc = new AccumulatorStack(network); + acc.init(internalBoard); + + System.out.println(internalBoard); + System.out.println(NNUE.evaluate(internalBoard, network, acc)); + break; + case "go": + Limits limits = new Limits(); + limits.setTime(157680000000L); + + for (int i = 1; i < fullCommand.length; i++) + { + if (fullCommand[i].equals("infinite")) + { + limits.setTime(157680000000L); + break; + } + + if ((fullCommand[i].equals("wtime") && Side.WHITE.equals(internalBoard.getSideToMove())) + || (fullCommand[i].equals("btime") && Side.BLACK.equals(internalBoard.getSideToMove()))) + { + limits.setTime(Long.parseLong(fullCommand[i + 1])); + } + + if ((fullCommand[i].equals("winc") && Side.WHITE.equals(internalBoard.getSideToMove())) + || (fullCommand[i].equals("binc") && Side.BLACK.equals(internalBoard.getSideToMove()))) + { + limits.setIncrement(Long.parseLong(fullCommand[i + 1])); + } + + if (fullCommand[i].equals("depth")) + { + limits.setDepth(Integer.parseInt(fullCommand[i + 1])); + limits.setTime(157680000000L); + break; + } + + if (fullCommand[i].equals("nodes")) + { + limits.setNodes(Long.parseLong(fullCommand[i + 1])); + limits.setTime(157680000000L); + break; + } + + if (fullCommand[i].equals("movetime")) + { + limits.setTime(Long.parseLong(fullCommand[i + 1])); + limits.setIncrement(0); + limits.setMovesToGo(-1); + } + + if (fullCommand[i].equals("movestogo")) + { + limits.setMovesToGo(Integer.parseInt(fullCommand[i + 1])); + } + } + + engine.nextMove(internalBoard.clone(), limits); + break; + case "position": + for (int i = 1; i < fullCommand.length; i++) + { + if (fullCommand[i].equals("startpos")) + { + internalBoard = new Board(); + } + if (fullCommand[i].equals("fen")) + { + internalBoard = new Board(); + internalBoard.loadFromFen( + fullCommand[i + 1] + " " + fullCommand[i + 2] + " " + fullCommand[i + 3] + " " + + fullCommand[i + 4] + " " + fullCommand[i + 5] + " " + fullCommand[i + 6]); + } + if (fullCommand[i].equals("moves")) + { + for (int j = i + 1; j < fullCommand.length; j++) + { + internalBoard.doMove(fullCommand[j]); + } + break; + } + } + break; + case "option": + for (UCIOption option : options.values()) + { + System.out.println(option); + } + break; + case "stop": + engine.stop(); + break; + case "setoption": + String key = ""; + for (int i = 1; i < fullCommand.length; i++) + { + if (fullCommand[i].equals("name")) + { + key = fullCommand[i + 1]; + } + if (fullCommand[i].equals("value") && options.containsKey(key)) + { + options.get(key).set(fullCommand[i + 1]); + } + } + break; + case "showvalues": + for (UCIOption option : options.values()) + { + System.out.println(option + " value " + option.getString()); + } + break; + case "bench": + depth = 10; + if (fullCommand.length > 1) + { + depth = Integer.parseInt(fullCommand[1]); + } + Bench.bench(engine, depth, false); + transpositionTable.clear(); + break; + } + } + + input.close(); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIListener.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIListener.java new file mode 100644 index 0000000..c4dbbcd --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIListener.java @@ -0,0 +1,84 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +import org.shawn.games.Serendipity.Search.AlphaBeta; +import org.shawn.games.Serendipity.Search.Listener.FinalReport; +import org.shawn.games.Serendipity.Search.Listener.ISearchListener; +import org.shawn.games.Serendipity.Search.Listener.SearchReport; + +import org.shawn.games.Serendipity.Chess.move.Move; + +public class UCIListener implements ISearchListener +{ + @Override + public void notify(SearchReport report) + { + StringBuffer pvString = new StringBuffer(); + + for (Move move : report.pv) + { + if (move == null) + { + break; + } + + pvString.append(" ").append(move); + } + + if (Math.abs(report.score) < AlphaBeta.MATE_EVAL - AlphaBeta.MAX_PLY) + { + int cp = WDLModel.normalizeEval(report.score, report.board); + int[] wdl = WDLModel.calculateWDL(report.score, report.board); + + System.out.printf( + "info depth %d seldepth %d nodes %d nps %d hashfull %d score cp %d wdl %d %d %d time %d pv%s\n", + report.depth, report.selDepth, report.nodes, report.nodes * 1000L / Math.max(1, report.ms), + report.hashfull, cp, wdl[0], wdl[1], wdl[2], report.ms, pvString); + } + + else + { + int mateInPly = AlphaBeta.MATE_EVAL - Math.abs(report.score); + int mateValue = mateInPly % 2 != 0 ? (mateInPly + 1) / 2 : -mateInPly / 2; + int[] wdl; + + if (mateValue < 0) + { + wdl = new int[] { 0, 0, 1000 }; + } + else + { + wdl = new int[] { 1000, 0, 0 }; + } + + System.out.printf( + "info depth %d seldepth %d nodes %d nps %d hashfull %d score mate %d wdl %d %d %d time %d pv %s\n", + report.depth, report.selDepth, report.nodes, report.nodes * 1000L / Math.max(1, report.ms), + report.hashfull, mateValue, wdl[0], wdl[1], wdl[2], report.ms, pvString); + } + } + + @Override + public void notify(FinalReport report) + { + System.out.println("bestmove " + (report.bestMove == null ? "(none)" : report.bestMove)); + } +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIOption.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIOption.java new file mode 100644 index 0000000..ddd4c2c --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/UCIOption.java @@ -0,0 +1,27 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +public interface UCIOption +{ + void set(String value); + + String getString(); +} diff --git a/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/WDLModel.java b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/WDLModel.java new file mode 100644 index 0000000..0acb965 --- /dev/null +++ b/Serendipity/src/main/java/org/shawn/games/Serendipity/UCI/WDLModel.java @@ -0,0 +1,90 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity.UCI; + +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.Piece; + +public class WDLModel +{ + private final static double[] as = { -117.29796837, 388.52982654, -512.96172771, 477.99147478 }; + private final static double[] bs = { -47.75093113, 118.81734426, -33.05800930, 94.01690687 }; + + @SuppressWarnings("unused") + private final static int NormalizeToPawnValue = 236; + + private final static int PAWN_VALUE = 1; + private final static int KNIGHT_VALUE = 3; + private final static int BISHOP_VALUE = 3; + private final static int ROOK_VALUE = 5; + private final static int QUEEN_VALUE = 9; + + private static int countMaterial(Board board) + { + return Long.bitCount(board.getBitboard(Piece.WHITE_PAWN)) * PAWN_VALUE + + Long.bitCount(board.getBitboard(Piece.WHITE_KNIGHT)) * KNIGHT_VALUE + + Long.bitCount(board.getBitboard(Piece.WHITE_BISHOP)) * BISHOP_VALUE + + Long.bitCount(board.getBitboard(Piece.WHITE_ROOK)) * ROOK_VALUE + + Long.bitCount(board.getBitboard(Piece.WHITE_QUEEN)) * QUEEN_VALUE + + Long.bitCount(board.getBitboard(Piece.BLACK_PAWN)) * PAWN_VALUE + + Long.bitCount(board.getBitboard(Piece.BLACK_KNIGHT)) * KNIGHT_VALUE + + Long.bitCount(board.getBitboard(Piece.BLACK_BISHOP)) * BISHOP_VALUE + + Long.bitCount(board.getBitboard(Piece.BLACK_ROOK)) * ROOK_VALUE + + Long.bitCount(board.getBitboard(Piece.BLACK_QUEEN)) * QUEEN_VALUE; + } + + private static double[] calculateParameters(Board board) + { + int material = countMaterial(board); + + material = Math.max(material, 17); + material = Math.min(material, 78); + + double m = material / 58.0; + + double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3]; + double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3]; + + return new double[] { a, b }; + } + + private static int calculateWinRate(int v, Board board) + { + double[] parameters = calculateParameters(board); + + return (int) (0.5 + 1000 / (1 + Math.exp((parameters[0] - (double) v) / parameters[1]))); + } + + public static int[] calculateWDL(int v, Board board) + { + int winRate = calculateWinRate(v, board); + int lossRate = calculateWinRate(-v, board); + int drawRate = 1000 - winRate - lossRate; + + return new int[] { winRate, drawRate, lossRate }; + } + + public static int normalizeEval(int v, Board board) + { + double a = calculateParameters(board)[0]; + + return (int) Math.round((100 * v) / a); + } +} diff --git a/Serendipity/src/main/resources/.gitignore b/Serendipity/src/main/resources/.gitignore new file mode 100644 index 0000000..771dc66 --- /dev/null +++ b/Serendipity/src/main/resources/.gitignore @@ -0,0 +1 @@ +*.nnue diff --git a/Serendipity/src/test/java/org/shawn/games/Serendipity/AccumulatorTest.java b/Serendipity/src/test/java/org/shawn/games/Serendipity/AccumulatorTest.java new file mode 100644 index 0000000..68f3d3a --- /dev/null +++ b/Serendipity/src/test/java/org/shawn/games/Serendipity/AccumulatorTest.java @@ -0,0 +1,86 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity; + +import org.shawn.games.Serendipity.NNUE.*; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.*; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +public class AccumulatorTest +{ + AccumulatorStack accumulators; + NNUE network; + Board board; + + public AccumulatorTest() throws IOException + { + network = new NNUE("/embedded.nnue"); + board = new Board(); + accumulators = new AccumulatorStack(network); + accumulators.init(board); + } + + public int evaluate(Board board) + { + int v = NNUE.evaluate(board, network, accumulators); + + return v; + } + + @Test + public void testAccumulators() + { + // 1. e4 d5 2. e5 f5 3. exf6 e5 4. fxg7 Bxg7 5. Ne2 Ne7 6. d3 O-O 7. Be3 c6 8. + // Qd2 Nd7 9. Nbc3 e4 10. O-O-O Kh8 11. g3 Re8 12. Bg2 Rg8 13. Qe1 Re8 14. Qg1 + // exd3 15. Kb1 dxe2 16. Ka1 e1=N + Move[] testGame = { new Move("e2e4", Side.WHITE), new Move("d7d5", Side.BLACK), new Move("e4e5", Side.WHITE), + new Move("f7f5", Side.BLACK), new Move("e5f6", Side.WHITE), new Move("e7e5", Side.BLACK), + new Move("f6g7", Side.WHITE), new Move("f8g7", Side.BLACK), new Move("g1e2", Side.WHITE), + new Move("g8e7", Side.BLACK), new Move("d2d3", Side.WHITE), new Move("e8g8", Side.BLACK), + new Move("c1e3", Side.WHITE), new Move("c7c6", Side.BLACK), new Move("d1d2", Side.WHITE), + new Move("b8d7", Side.BLACK), new Move("b1c3", Side.WHITE), new Move("e5e4", Side.BLACK), + new Move("e1c1", Side.WHITE), new Move("g8h8", Side.BLACK), new Move("g2g3", Side.WHITE), + new Move("f8e8", Side.BLACK), new Move("f1g2", Side.WHITE), new Move("e8g8", Side.BLACK), + new Move("d2e1", Side.WHITE), new Move("g8e8", Side.BLACK), new Move("e1g1", Side.WHITE), + new Move("e4d3", Side.BLACK), new Move("c1b1", Side.WHITE), new Move("d3e2", Side.BLACK), + new Move("b1a1", Side.WHITE), new Move("e2e1n", Side.BLACK) }; + + for (Move move : testGame) + { + AccumulatorDiff diff = board.doMove(move); + accumulators.push(board, move, diff); + } + + final int incrementallyUpdatedEvaluation = evaluate(board); + + accumulators.init(board); + + final int fullUpdatedEvaluation = evaluate(board); + + assertEquals(incrementallyUpdatedEvaluation, fullUpdatedEvaluation); + } +} diff --git a/Serendipity/src/test/java/org/shawn/games/Serendipity/SEETest.java b/Serendipity/src/test/java/org/shawn/games/Serendipity/SEETest.java new file mode 100644 index 0000000..ce55e6e --- /dev/null +++ b/Serendipity/src/test/java/org/shawn/games/Serendipity/SEETest.java @@ -0,0 +1,295 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import org.shawn.games.Serendipity.Chess.Attacks; +import org.shawn.games.Serendipity.Chess.Bitboard; +import org.shawn.games.Serendipity.Chess.Board; +import org.shawn.games.Serendipity.Chess.Piece; +import org.shawn.games.Serendipity.Chess.PieceType; +import org.shawn.games.Serendipity.Chess.Side; +import org.shawn.games.Serendipity.Chess.Square; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class SEETest +{ + private String rawTestString = "6k1/1pp4p/p1pb4/6q1/3P1pRr/2P4P/PP1Br1P1/5RKN w - - | f1f4 | -100 | P - R + B\n" + + "5rk1/1pp2q1p/p1pb4/8/3P1NP1/2P5/1P1BQ1P1/5RK1 b - - | d6f4 | 0 | -N + B\n" + + "4R3/2r3p1/5bk1/1p1r3p/p2PR1P1/P1BK1P2/1P6/8 b - - | h5g4 | 0\n" + + "4R3/2r3p1/5bk1/1p1r1p1p/p2PR1P1/P1BK1P2/1P6/8 b - - | h5g4 | 0\n" + + "4r1k1/5pp1/nbp4p/1p2p2q/1P2P1b1/1BP2N1P/1B2QPPK/3R4 b - - | g4f3 | 0\n" + + "2r1r1k1/pp1bppbp/3p1np1/q3P3/2P2P2/1P2B3/P1N1B1PP/2RQ1RK1 b - - | d6e5 | 100 | P\n" + + "7r/5qpk/p1Qp1b1p/3r3n/BB3p2/5p2/P1P2P2/4RK1R w - - | e1e8 | 0\n" + + "6rr/6pk/p1Qp1b1p/2n5/1B3p2/5p2/P1P2P2/4RK1R w - - | e1e8 | -500 | -R\n" + + "7r/5qpk/2Qp1b1p/1N1r3n/BB3p2/5p2/P1P2P2/4RK1R w - - | e1e8 | -500 | -R\n" + + "6RR/4bP2/8/8/5r2/3K4/5p2/4k3 w - - | f7f8q | 200 | B - P\n" + + "6RR/4bP2/8/8/5r2/3K4/5p2/4k3 w - - | f7f8n | 200 | N - P\n" + + "7R/5P2/8/8/6r1/3K4/5p2/4k3 w - - | f7f8q | 800 | Q - P\n" + + "7R/5P2/8/8/6r1/3K4/5p2/4k3 w - - | f7f8b | 200 | B - P\n" + + "7R/4bP2/8/8/1q6/3K4/5p2/4k3 w - - | f7f8r | -100 | -P\n" + + "8/4kp2/2npp3/1Nn5/1p2PQP1/7q/1PP1B3/4KR1r b - - | h1f1 | 0\n" + + "8/4kp2/2npp3/1Nn5/1p2P1P1/7q/1PP1B3/4KR1r b - - | h1f1 | 0\n" + + "2r2r1k/6bp/p7/2q2p1Q/3PpP2/1B6/P5PP/2RR3K b - - | c5c1 | 100 | R - Q + R\n" + + "r2qk1nr/pp2ppbp/2b3p1/2p1p3/8/2N2N2/PPPP1PPP/R1BQR1K1 w kq - | f3e5 | 100 | P\n" + + "6r1/4kq2/b2p1p2/p1pPb3/p1P2B1Q/2P4P/2B1R1P1/6K1 w - - | f4e5 | 0\n" + + "3q2nk/pb1r1p2/np6/3P2Pp/2p1P3/2R4B/PQ3P1P/3R2K1 w - h6 | g5h6 | 0\n" + + "3q2nk/pb1r1p2/np6/3P2Pp/2p1P3/2R1B2B/PQ3P1P/3R2K1 w - h6 | g5h6 | 100 | P\n" + + "2r4r/1P4pk/p2p1b1p/7n/BB3p2/2R2p2/P1P2P2/4RK2 w - - | c3c8 | 500 | R\n" +// + "2r5/1P4pk/p2p1b1p/5b1n/BB3p2/2R2p2/P1P2P2/4RK2 w - - | c3c8 | 500 | R\n" // CANT PASS + + "2r4k/2r4p/p7/2b2p1b/4pP2/1BR5/P1R3PP/2Q4K w - - | c3c5 | 300 | B\n" + + "8/pp6/2pkp3/4bp2/2R3b1/2P5/PP4B1/1K6 w - - | g2c6 | -200 | P - B\n" + + "4q3/1p1pr1k1/1B2rp2/6p1/p3PP2/P3R1P1/1P2R1K1/4Q3 b - - | e6e4 | -400 | P - R\n" + + "4q3/1p1pr1kb/1B2rp2/6p1/p3PP2/P3R1P1/1P2R1K1/4Q3 b - - | h7e4 | 100 | P\n" + + "3r3k/3r4/2n1n3/8/3p4/2PR4/1B1Q4/3R3K w - - | d3d4 | -100 | P - R + N - P + N - B + R - Q + R\n" + + "1k1r4/1ppn3p/p4b2/4n3/8/P2N2P1/1PP1R1BP/2K1Q3 w - - | d3e5 | 100 | N - N + B - R + N\n" + + "1k1r3q/1ppn3p/p4b2/4p3/8/P2N2P1/1PP1R1BP/2K1Q3 w - - | d3e5 | -200 | P - N\n" + + "rnb2b1r/ppp2kpp/5n2/4P3/q2P3B/5R2/PPP2PPP/RN1QKB2 w Q - | h4f6 | 100 | N - B + P\n" + + "r2q1rk1/2p1bppp/p2p1n2/1p2P3/4P1b1/1nP1BN2/PP3PPP/RN1QR1K1 b - - | g4f3 | 0 | N - B\n" + + "r1bqkb1r/2pp1ppp/p1n5/1p2p3/3Pn3/1B3N2/PPP2PPP/RNBQ1RK1 b kq - | c6d4 | 0 | P - N + N - P\n" + + "r1bq1r2/pp1ppkbp/4N1p1/n3P1B1/8/2N5/PPP2PPP/R2QK2R w KQ - | e6g7 | 0 | B - N\n" + + "r1bq1r2/pp1ppkbp/4N1pB/n3P3/8/2N5/PPP2PPP/R2QK2R w KQ - | e6g7 | 300 | B\n" + + "rnq1k2r/1b3ppp/p2bpn2/1p1p4/3N4/1BN1P3/PPP2PPP/R1BQR1K1 b kq - | d6h2 | -200 | P - B\n" + + "rn2k2r/1bq2ppp/p2bpn2/1p1p4/3N4/1BN1P3/PPP2PPP/R1BQR1K1 b kq - | d6h2 | 100 | P\n" + + "r2qkbn1/ppp1pp1p/3p1rp1/3Pn3/4P1b1/2N2N2/PPP2PPP/R1BQKB1R b KQq - | g4f3 | 100 | N - B + P\n" + + "rnbq1rk1/pppp1ppp/4pn2/8/1bPP4/P1N5/1PQ1PPPP/R1B1KBNR b KQ - | b4c3 | 0 | N - B\n" + + "r4rk1/3nppbp/bq1p1np1/2pP4/8/2N2NPP/PP2PPB1/R1BQR1K1 b - - | b6b2 | -800 | P - Q\n" + + "r4rk1/1q1nppbp/b2p1np1/2pP4/8/2N2NPP/PP2PPB1/R1BQR1K1 b - - | f6d5 | -200 | P - N\n" + + "1r3r2/5p2/4p2p/2k1n1P1/2PN1nP1/1P3P2/8/2KR1B1R b - - | b8b3 | -400 | P - R\n" + + "1r3r2/5p2/4p2p/4n1P1/kPPN1nP1/5P2/8/2KR1B1R b - - | b8b4 | 100 | P\n" + + "2r2rk1/5pp1/pp5p/q2p4/P3n3/1Q3NP1/1P2PP1P/2RR2K1 b - - | c8c1 | 0 | R - R\n" + + "5rk1/5pp1/2r4p/5b2/2R5/6Q1/R1P1qPP1/5NK1 b - - | f5c2 | -100 | P - B + R - Q + R\n" + + "1r3r1k/p4pp1/2p1p2p/qpQP3P/2P5/3R4/PP3PP1/1K1R4 b - - | a5a2 | -800 | P - Q\n" + + "1r5k/p4pp1/2p1p2p/qpQP3P/2P2P2/1P1R4/P4rP1/1K1R4 b - - | a5a2 | 100 | P\n" + + "r2q1rk1/1b2bppp/p2p1n2/1ppNp3/3nP3/P2P1N1P/BPP2PP1/R1BQR1K1 w - - | d5e7 | 0 | B - N\n" + + "rnbqrbn1/pp3ppp/3p4/2p2k2/4p3/3B1K2/PPP2PPP/RNB1Q1NR w - - | d3e4 | 100 | P\n" + + "rnb1k2r/p3p1pp/1p3p1b/7n/1N2N3/3P1PB1/PPP1P1PP/R2QKB1R w KQkq - | e4d6 | -200 | -N + P\n" + + "r1b1k2r/p4npp/1pp2p1b/7n/1N2N3/3P1PB1/PPP1P1PP/R2QKB1R w KQkq - | e4d6 | 0 | -N + N\n" + + "2r1k2r/pb4pp/5p1b/2KB3n/4N3/2NP1PB1/PPP1P1PP/R2Q3R w k - | d5c6 | -300 | -B\n" + + "2r1k2r/pb4pp/5p1b/2KB3n/1N2N3/3P1PB1/PPP1P1PP/R2Q3R w k - | d5c6 | 0 | -B + B\n" + + "2r1k3/pbr3pp/5p1b/2KB3n/1N2N3/3P1PB1/PPP1P1PP/R2Q3R w - - | d5c6 | -300 | -B + B - N\n" + + "5k2/p2P2pp/8/1pb5/1Nn1P1n1/6Q1/PPP4P/R3K1NR w KQ - | d7d8q | 800 | (Q - P)\n" + + "r4k2/p2P2pp/8/1pb5/1Nn1P1n1/6Q1/PPP4P/R3K1NR w KQ - | d7d8q | -100 | (Q - P) - Q\n" + + "5k2/p2P2pp/1b6/1p6/1Nn1P1n1/8/PPP4P/R2QK1NR w KQ - | d7d8q | 200 | (Q - P) - Q + B\n" + + "4kbnr/p1P1pppp/b7/4q3/7n/8/PP1PPPPP/RNBQKBNR w KQk - | c7c8q | -100 | (Q - P) - Q\n" + + "4kbnr/p1P1pppp/b7/4q3/7n/8/PPQPPPPP/RNB1KBNR w KQk - | c7c8q | 200 | (Q - P) - Q + B\n" + + "4kbnr/p1P1pppp/b7/4q3/7n/8/PPQPPPPP/RNB1KBNR w KQk - | c7c8q | 200 | (Q - P)\n" + + "4kbnr/p1P4p/b1q5/5pP1/4n3/5Q2/PP1PPP1P/RNB1KBNR w KQk f6 | g5f6 | 0 | P - P\n" + + "4kbnr/p1P4p/b1q5/5pP1/4n3/5Q2/PP1PPP1P/RNB1KBNR w KQk f6 | g5f6 | 0 | P - P\n" + + "4kbnr/p1P4p/b1q5/5pP1/4n2Q/8/PP1PPP1P/RNB1KBNR w KQk f6 | g5f6 | 0 | P - P\n" + + "1n2kb1r/p1P4p/2qb4/5pP1/4n2Q/8/PP1PPP1P/RNB1KBNR w KQk - | c7b8q | 200 | N + (Q - P) - Q\n" + + "rnbqk2r/pp3ppp/2p1pn2/3p4/3P4/N1P1BN2/PPB1PPPb/R2Q1RK1 w kq - | g1h2 | 300 | B\n" + + "3N4/2K5/2n5/1k6/8/8/8/8 b - - | c6d8 | 0 | N - N\n" + + "3n3r/2P5/8/1k6/8/8/3Q4/4K3 w - - | c7d8q | 700 | (N + Q - P) - Q + R\n" + + "r2n3r/2P1P3/4N3/1k6/8/8/8/4K3 w - - | e6d8 | 300 | N\n" + + "8/8/8/1k6/6b1/4N3/2p3K1/3n4 w - - | e3d1 | 0 | N - N\n" + + "8/8/1k6/8/8/2N1N3/4p1K1/3n4 w - - | c3d1 | 100 | N - (N + Q - P) + Q\n" + + "r1bqk1nr/pppp1ppp/2n5/1B2p3/1b2P3/5N2/PPPP1PPP/RNBQK2R w KQkq - | e1g1 | 0"; + + private class SEE + { + private static int[] SEEPieceValues = new int[] { 100, 300, 300, 500, 900, 0 }; + + public static int moveEstimatedValue(Board board, Move move) + { + // Start with the value of the piece on the target square + int value = !board.getPiece(move.getTo()).equals(Piece.NONE) + ? SEEPieceValues[board.getPiece(move.getTo()).getPieceType().ordinal()] + : 0; + + // Factor in the new piece's value and remove our promoted pawn + if (!Piece.NONE.equals(move.getPromotion())) + value += SEEPieceValues[move.getPromotion().getPieceType().ordinal()] + - SEEPieceValues[PieceType.PAWN.ordinal()]; + + // Target square is encoded as empty for enpass moves + else if (PieceType.PAWN.equals(board.getPiece(move.getFrom()).getPieceType()) + && board.getEnPassant().equals(move.getTo())) + value = SEEPieceValues[PieceType.PAWN.ordinal()]; + + return value; + } + + public static boolean staticExchangeEvaluation(Board board, Move move, int threshold) + { + Square from, to; + PieceType nextVictim; + Side colour; + int balance; + long bishops, rooks, occupied, attackers, myAttackers; + boolean isPromotion, isEnPassant; + + // Unpack move information + from = move.getFrom(); + to = move.getTo(); + + isPromotion = !Piece.NONE.equals(move.getPromotion()); + isEnPassant = PieceType.PAWN.equals(board.getPiece(from).getPieceType()) && board.getEnPassant().equals(to); + + // Next victim is moved piece or promotion type + nextVictim = !isPromotion ? board.getPiece(from).getPieceType() : move.getPromotion().getPieceType(); + + // Balance is the value of the move minus threshold. Function + // call takes care for Enpass, Promotion and Castling moves. + balance = moveEstimatedValue(board, move) - threshold; + + // Best case still fails to beat the threshold + if (balance < 0) + return false; + + // Worst case is losing the moved piece + balance -= SEEPieceValues[nextVictim.ordinal()]; + + // If the balance is positive even if losing the moved piece, + // the exchange is guaranteed to beat the threshold. + if (balance >= 0) + return true; + + // Grab sliders for updating revealed attackers + bishops = board.getBitboard(Piece.BLACK_BISHOP) | board.getBitboard(Piece.WHITE_BISHOP) + | board.getBitboard(Piece.BLACK_QUEEN) | board.getBitboard(Piece.WHITE_QUEEN); + rooks = board.getBitboard(Piece.BLACK_ROOK) | board.getBitboard(Piece.WHITE_ROOK) + | board.getBitboard(Piece.BLACK_QUEEN) | board.getBitboard(Piece.WHITE_QUEEN); + + // Let occupied suppose that the move was actually made + occupied = board.getBitboard(); + occupied = (occupied ^ (1L << from.ordinal())) | (1L << to.ordinal()); + if (isEnPassant) + occupied ^= (1L << board.getEnPassant().ordinal()); + + // Get all pieces which attack the target square. And with occupied + // so that we do not let the same piece attack twice + attackers = board.squareAttackedBy(to, board.getSideToMove(), occupied) + | board.squareAttackedBy(to, board.getSideToMove().flip(), occupied) & occupied; + + // Now our opponents turn to recapture + colour = board.getSideToMove().flip(); + + while (true) + { + // If we have no more attackers left we lose + myAttackers = attackers & board.getBitboard(colour); + + if (myAttackers == 0) + break; + + if ((myAttackers & board.getBitboard(Piece.make(colour, PieceType.PAWN))) != 0L) + { + nextVictim = PieceType.PAWN; + } + + else if ((myAttackers & board.getBitboard(Piece.make(colour, PieceType.KNIGHT))) != 0L) + { + nextVictim = PieceType.KNIGHT; + } + + else if ((myAttackers & board.getBitboard(Piece.make(colour, PieceType.BISHOP))) != 0L) + { + nextVictim = PieceType.BISHOP; + } + + else if ((myAttackers & board.getBitboard(Piece.make(colour, PieceType.ROOK))) != 0L) + { + nextVictim = PieceType.ROOK; + } + + else if ((myAttackers & board.getBitboard(Piece.make(colour, PieceType.QUEEN))) != 0L) + { + nextVictim = PieceType.QUEEN; + } + + else if ((myAttackers & board.getBitboard(Piece.make(colour, PieceType.KING))) != 0L) + { + nextVictim = PieceType.KING; + } + + else + { + assert (false); + } + + // Remove this attacker from the occupied + occupied ^= (1L << Bitboard + .bitScanForward(myAttackers & board.getBitboard(Piece.make(colour, nextVictim)))); + + // A diagonal move may reveal bishop or queen attackers + if (nextVictim.equals(PieceType.PAWN) || nextVictim.equals(PieceType.BISHOP) + || nextVictim.equals(PieceType.QUEEN)) + attackers |= Attacks.getBishopAttacks(occupied, to) & bishops; + + // A vertical or horizontal move may reveal rook or queen attackers + if (nextVictim.equals(PieceType.ROOK) || nextVictim.equals(PieceType.QUEEN)) + attackers |= Attacks.getRookAttacks(occupied, to) & rooks; + + // Make sure we did not add any already used attacks + attackers &= occupied; + + // Swap the turn + colour = colour.flip(); + + // Negamax the balance and add the value of the next victim + balance = -balance - 1 - SEEPieceValues[nextVictim.ordinal()]; + + // If the balance is non-negative after giving away our piece then we win + if (balance >= 0) + { + // As a slide speed up for move legality checking, if our last attacking + // piece is a king, and our opponent still has attackers, then we've + // lost as the move we followed would be illegal + if (nextVictim.equals(PieceType.KING) && (attackers & board.getBitboard(colour)) != 0) + colour = colour.flip(); + + break; + } + } + + // Side to move after the loop loses + return !board.getSideToMove().equals(colour); + } + } + + @Test + public void testSEE() + { + Board board = new Board(); + + for (String s : rawTestString.split("\n")) + { + String[] data = s.split("\\s\\|\\s"); + + board.loadFromFen(data[0]); + Move move = new Move(data[1], board.getSideToMove()); + + int expectedValue = Integer.parseInt(data[2]); + + if (!SEE.staticExchangeEvaluation(board, move, expectedValue)) + { + System.out.println(s); + } + + assertFalse(SEE.staticExchangeEvaluation(board, move, expectedValue + 1)); + assertTrue(SEE.staticExchangeEvaluation(board, move, expectedValue)); + } + } +} diff --git a/Serendipity/src/test/java/org/shawn/games/Serendipity/TranspositionTableTest.java b/Serendipity/src/test/java/org/shawn/games/Serendipity/TranspositionTableTest.java new file mode 100644 index 0000000..d35a7b4 --- /dev/null +++ b/Serendipity/src/test/java/org/shawn/games/Serendipity/TranspositionTableTest.java @@ -0,0 +1,58 @@ +/* + This file is part of Serendipity, an UCI chess engine written in Java. + + Copyright (C) 2024-2025 Shawn Xu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package org.shawn.games.Serendipity; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import org.junit.Test; +import org.shawn.games.Serendipity.Search.TranspositionTable; + +import org.shawn.games.Serendipity.Chess.*; +import org.shawn.games.Serendipity.Chess.move.Move; + +public class TranspositionTableTest +{ + @Test + public void testTT() + { + Board board = new Board(); + TranspositionTable tt = new TranspositionTable(4); + + assertFalse(tt.probe(0).hit()); + + tt.write(null, board.getIncrementalHashKey(), TranspositionTable.NODETYPE_EXACT, 12, 2, null, 0, true); + assertEquals(12, tt.probe(board.getIncrementalHashKey()).getDepth()); + assertEquals(2, tt.probe(board.getIncrementalHashKey()).getEvaluation()); + assertTrue(tt.probe(board.getIncrementalHashKey()).verifySignature(board.getIncrementalHashKey())); + assertTrue(tt.probe(board.getIncrementalHashKey()).wasPV()); + + tt.write(null, board.getIncrementalHashKey(), TranspositionTable.NODETYPE_NONE, TranspositionTable.DEPTH_QS, + -6900, new Move(Square.E2, Square.E4), -200, false); + assertEquals(TranspositionTable.NODETYPE_NONE, tt.probe(board.getIncrementalHashKey()).getNodeType()); + assertEquals(TranspositionTable.DEPTH_QS, tt.probe(board.getIncrementalHashKey()).getDepth()); + assertEquals(-6900, tt.probe(board.getIncrementalHashKey()).getEvaluation()); + assertEquals(-200, tt.probe(board.getIncrementalHashKey()).getStaticEval()); + assertTrue(tt.probe(board.getIncrementalHashKey()).getMove().equals(new Move(Square.E2, Square.E4))); + assertTrue(tt.probe(board.getIncrementalHashKey()).verifySignature(board.getIncrementalHashKey())); + assertFalse(tt.probe(board.getIncrementalHashKey()).wasPV()); + } +} diff --git a/header.sh b/header.sh new file mode 100644 index 0000000..10c170d --- /dev/null +++ b/header.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# Taken from https://web.archive.org/web/20240813210415/https://coderwall.com/p/ssuaxa/how-to-make-a-jar-file-linux-executable + +MYSELF=`which "$0" 2>/dev/null` + +[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0" + +java=java + +if test -n "$JAVA_HOME"; then + java="$JAVA_HOME/bin/java" +fi + +exec "$java" --add-modules=jdk.incubator.vector -XX:+UseParallelGC $java_args -jar $MYSELF "$@" + +exit 1 diff --git a/makefile b/makefile index 5857340..10e74e1 100644 --- a/makefile +++ b/makefile @@ -1,35 +1,40 @@ -# Detect the operating system -ifeq ($(OS),Windows_NT) - EXE_EXT := .exe - MOVE_CMD := move - PATH_SEPARATOR := \$() -else - EXE_EXT := - MOVE_CMD := mv - PATH_SEPARATOR := / +# This file is part of Serendipity, an UCI chess engine written in Java. +# +# Copyright (C) 2024-2025 Shawn Xu +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +EXE = Serendipity-Dev +EMBEDDED_NET_LOCATION = ./Serendipity/src/main/resources/embedded.nnue +NET_NAME = net1.nnue +ifndef MAVEN_EXE + MAVEN_EXE = mvn endif -ifdef CPU - SUFX := _$(CPU) +all: +ifdef EVALFILE + cp $(EVALFILE) $(EMBEDDED_NET_LOCATION) else - SUFX := + $(MAKE) net endif - -EXE := Perseus - -# Default target (release build) -all: release - -# Release target -release: - $(MAKE) -C src release EXE=$(EXE)$(EXE_EXT) - @$(MOVE_CMD) src$(PATH_SEPARATOR)$(EXE)$(EXE_EXT) $(EXE)$(SUFX)$(EXE_EXT) - -# Debug target -debug: - $(MAKE) -C src debug EXE=$(EXE)$(EXE_EXT) - @$(MOVE_CMD) src$(PATH_SEPARATOR)$(EXE)$(EXE_EXT) $(EXE)$(SUFX)$(EXE_EXT) - -# Clean target -clean: - $(MAKE) -C src clean EXE=$(EXE)$(EXE_EXT) +ifdef JAVA_HOME + JAVA_HOME=$(JAVA_HOME) $(MAVEN_EXE) -f ./Serendipity/pom.xml package +else + $(MAVEN_EXE) -f ./Serendipity/pom.xml package +endif + cat header.sh ./Serendipity/target/Serendipity-Test.jar > $(EXE) + chmod +x $(EXE) + cp ./Serendipity/target/Serendipity-Test.jar Serendipity.jar +net: + wget -O $(EMBEDDED_NET_LOCATION) https://github.com/xu-shawn/Serendipity-Networks/raw/main/$(NET_NAME) diff --git a/perft.txt b/perft.txt deleted file mode 100644 index 184155d..0000000 --- a/perft.txt +++ /dev/null @@ -1,6752 +0,0 @@ -r1bq1bnr/pppk1p2/3p4/6pp/3PPpnP/N1P2PP1/PP2K3/R2Q1BNR w - -,30,948,29183,914777,28805208,912753139 -1n3bkr/2B4p/6b1/pppn4/P2pP3/3P4/2PN1K2/R7 b - -,27,909,24213,739398,19815361,569283806 -3N3k/B4P2/2r4P/1bn5/3K2p1/6P1/8/4R3 b - -,24,609,14112,347098,7946349,198285905 -1r1q1b1r/2n2k1b/p2p3p/P1p1pp1R/3P1P2/P4Qp1/3K2B1/R1B3N1 w - -,42,1521,61149,2137522,84317091,2900125477 -8/2k5/np6/6N1/1pp2P2/8/8/3K4 b - -,12,142,1681,19693,239437,2755503 -3rkb2/1q1b4/3pp2r/1pp1n3/7p/nPPP4/4N1P1/1RBB1K1R w - -,26,1038,26307,1026466,26898917,1047269119 -1rb3r1/p4kb1/B2ppn2/3P2p1/P3P1Pp/R1p2N1P/2P5/1N1QBK1R w - -,38,1102,40799,1218263,45243382,1363443039 -8/8/2kNp3/4P2p/K3P2P/3B4/8/8 w - -,18,72,1230,5629,94988,418127 -1n6/3q1k2/3r4/4KP1p/8/7R/8/8 b - -,32,346,12144,135202,4779064,55778186 -rnbqkbnr/ppppppp1/8/7p/8/P3P3/1PPP1PPP/RNBQKBNR b KQkq -,21,607,14114,420571,10689894,328853102 -2b1k3/p3p1rp/1r2P3/1np3p1/1P3nP1/PQNP1P2/5K1P/3R3R b - -,34,1117,36991,1213503,39414566,1302733670 -1n1bk3/r1Q2N2/b2P1q1p/RP3P2/1P6/2Rp1PK1/8/5B1q w - -,40,1269,35056,1243087,35663966,1338062020 -rB5r/pp4k1/5n2/3qp1pp/Pb3p2/1P1P3b/R2QPPP1/1N2KBNR b K -,60,1513,84307,2325605,121928751,3626493565 -5Nr1/1k6/2nN4/8/3p4/6b1/7n/3K4 b - -,7,105,2839,40819,1169688,16611178 -6B1/5rk1/2b5/6bn/2np3r/2p5/3R4/3K4 b - -,56,744,38212,539219,25908208,397007280 -rn1qk2r/p2b2bp/1pp1pp2/1N1p1np1/2B2P2/1PPPP1PP/P7/R1BQK1NR b KQkq -,31,963,27853,897649,26929134,890765778 -rnkq1bnr/4pp2/2pQ2pp/pp6/1P5N/2P4P/P2PPP2/RNB1KB1b w Q -,36,857,29373,807330,26996998,806839269 -5r2/1pk2Q2/p7/2p1Pb1p/R1K2pPP/1PPR4/4N3/1N6 b - -,6,255,4726,168011,3159583,109193455 -N1b2knr/ppqp2bp/5p2/2p1p1p1/6P1/4PP1P/PPPPK3/R1BQnBNR w - -,19,500,10724,293325,6812997,193430496 -5k2/8/1P6/pR4P1/8/8/1K4B1/3r4 w - -,23,430,9562,167237,3830373,64161930 -8/p7/P3k2B/1K6/8/7p/8/8 w - -,13,103,1399,10741,150756,1240061 -1n4R1/B4r1k/bP6/4p3/2pP1P1P/5p2/3n4/4R1K1 b - -,26,730,17565,467772,11377140,293416946 -1R6/2k5/4r3/pr3p2/1b2p2p/pRP4B/4NP1P/4K3 w - -,29,791,22411,600709,17267028,462830428 -rnb1kb1r/p1qppppp/1pp2n2/7P/8/P1NP4/1PP1PPP1/R1BQKBNR b KQkq -,28,857,25426,788005,24212778,761333794 -r1n1k1r1/5p2/2p2P2/1P2b3/p2p3p/P1P1p3/NB2P3/2R1KB2 w - -,13,407,5902,178707,2857039,84338421 -4k1Q1/8/4q3/8/5B2/2K5/8/8 b - -,3,85,1682,37238,753483,17178735 -7q/p1rbn1p1/P1ppR3/1PP2P1k/1B1P3p/1Q5P/1R2K3/1N6 w - -,44,1060,45953,1076551,45122203,1074661886 -r1bq1bn1/pppp1ppr/2nkp3/7p/1PP5/3P4/P3PPPP/RN1QKBNR w KQ -,24,690,17769,506299,13638785,389867861 -8/7R/b1NkP3/P4n2/6P1/7p/8/K7 b - -,19,450,8119,173692,3077288,64456642 -2N5/3N3k/3p3n/1p6/P1PP1Q1p/1P3P2/7P/2K2BrR b - -,22,794,13451,504671,8296592,315157920 -1B6/6r1/1bB4k/Pp3R2/4KN1p/8/8/8 b - -,26,807,17984,570921,12223098,390263068 -2r3nr/4p1k1/q7/1bp1P3/4BPpP/4b1P1/7K/1R4NR b - -,47,1210,56249,1424338,65251704,1635452511 -4k1r1/1b1nb3/1B2n3/1p1r2p1/p1p4p/P3pPP1/3N1N2/R1K2B1R w - -,34,1517,48876,2118963,67939866,2895512114 -1r3rk1/np2p1b1/1p1N1pp1/1qpn1b1p/PP5P/3P1PP1/4B3/1R1KR3 w - -,25,1004,23108,903575,21423460,831490058 -3b1R2/k7/B7/8/3p2PP/2NK4/6b1/8 b - -,21,579,10086,269977,4652556,121545164 -r1bqkbnr/p2ppppp/np6/2p5/P7/7N/RPPPPPPP/1NBQKB1R w Kkq -,21,421,9904,227500,5891946,150605381 -1b6/4P1r1/6b1/7P/2P1k3/r7/2R1p3/4K3 w - -,16,498,7816,249515,4169392,136843652 -1r1qkb1r/7b/p2p3p/P1pnpp1R/3P1P2/P4Qp1/6B1/R1BK2N1 b k -,39,1349,51136,1859239,68521879,2550055085 -7n/1B6/3p1N2/4k1n1/8/8/4K3/q7 w - -,21,579,9058,258452,3804248,108870771 -5N2/4k3/2Bp1b2/3q4/4p1nR/8/4K3/7n b - -,38,682,22905,437881,14586174,289293184 -8/2R5/7k/4P2p/7p/5n2/6K1/1B6 b - -,9,202,1553,35954,309662,7086258 -6N1/8/3pk2n/6n1/2B1p3/8/1q6/3K4 b - -,4,54,1709,18966,570797,6855565 -q1b2b1r/1P2n2k/p7/3PpNp1/2P2p1P/N2KPPP1/P3B3/B3R1R1 b - -,23,904,23422,890825,24904947,936088008 -3r2N1/r4b2/2p1k2p/P2p2n1/3Pp3/1P2K3/2B2R1R/B7 w - -,29,716,21862,545356,16991960,433276533 -r1bqkbn1/p2p1pp1/np5r/2p1p3/1P3NPp/3P1P1B/P1P1P2P/RNBQK2R b KQq -,33,1014,32531,1012871,32392571,1021036480 -4k2r/6pp/5n2/p2p1P2/1bP1N3/7N/2Rp1K1P/1r4R1 w - -,33,1148,31950,1109396,30629829,1061375332 -r1bqkbnr/p1p2ppp/2n5/1p1pp3/6P1/PP3P2/2PPP1BP/RNBQK1NR b KQkq -,39,759,29231,624373,24042145,558450140 -r2b4/r4k2/8/1p6/3p1KP1/R1N3B1/1p6/6N1 b - -,32,795,25501,640016,21060669,534062082 -6k1/3P4/p7/PQ6/N7/2p4B/2R1p3/4K3 b - -,6,217,1195,43303,252303,9183715 -1rb1qbn1/ppppp1p1/6k1/P7/P6p/B1Pr1P1P/3P2PN/RN1Q1KR1 w - -,22,606,14382,406668,10390026,304353981 -r3kb1r/1b1pn1pp/2p1p3/pp3p2/PP2P1P1/N1N5/2PP2P1/R1BQ1BKR w kq -,35,976,35119,962260,35529916,973732915 -r1b2br1/1p1k4/p4Q2/q1p1P2p/P4pnP/1PPK1P2/4N3/RN1R4 b - -,28,892,19903,626388,15485007,482559333 -3k4/R6B/Pprn4/2p4P/1NP1p1p1/3R4/8/3K4 w - -,32,304,9438,121984,3698441,54994926 -b1r1k3/8/1N6/8/2p2P1n/4B2B/1K6/n2R4 w - -,40,818,28627,639894,21230291,497155186 -6n1/r4b2/p2p4/Pk2P3/2p1P2p/7N/B2K2P1/3NQ1R1 w - -,27,523,15274,310186,9709802,204765135 -3k2nN/8/3p1qB1/3P2b1/4pP1R/7p/4r3/2nK4 w - -,15,524,7514,270247,4078395,147475931 -rn1q1b2/p2p2p1/1pp1pnk1/5p2/PPb5/R4R1B/3PPP2/1NBQK1N1 w - -,28,935,26895,901958,27312513,916845452 -1Kr4k/8/5N2/1P6/8/5n2/8/8 w - -,3,53,662,12350,134870,2660283 -N4b2/1r6/5Pk1/8/qpP3P1/4B3/B1n5/2K2R2 w - -,29,993,25887,880676,22160342,757671191 -3k4/8/8/2n1Q2p/1r5P/6R1/8/2K5 b - -,24,821,13386,450321,7537886,243691616 -8/8/1k2N3/1p2PB2/1p1p1r2/3K4/3n4/7q b - -,40,533,19260,269972,9265806,129304720 -4R3/3k3r/p4P1p/P2p3P/1b6/1b1p2P1/3R4/5K2 b - -,22,597,13111,321393,7284540,171578484 -4b3/2b4P/8/4k3/8/8/5r2/4n1K1 w - -,6,152,1177,32729,350834,10061706 -3k3r/2R4p/8/p2p1P2/2P3n1/3K3N/2RN3P/2bq3r w - -,23,635,12230,364803,7645284,243664666 -8/n2k4/p2p1Q2/P1pP4/8/P2K3N/2BBr2R/b7 b - -,23,863,17292,620760,12884978,460191711 -8/2NB2k1/8/2P5/8/8/K7/8 w - -,21,159,3185,15149,300453,1621375 -5R1r/1k6/5P2/5N2/2p2K2/2PN4/3r4/8 b - -,24,657,15109,394096,9334553,236339389 -3N4/7k/7B/P3P2P/1pKpb1P1/4P3/8/8 w - -,17,292,5009,68909,1210763,15430086 -r3kb1r/pbnpp2p/2p2p1p/Rp6/1q1PPP2/4B3/2P3PP/1NK2BNR w q -,29,990,25772,885082,24179960,833948896 -5k2/7Q/5r1P/pppR3r/1P6/P1b1n1K1/2N5/5B2 w - -,38,1303,40814,1312103,42722425,1320940640 -2B2n1k/8/6p1/4p2p/7P/5K2/8/6b1 b - -,15,155,2481,28078,459755,5408827 -3n4/1B5k/4p1b1/1p2P2p/p6P/Q3P3/8/2N1K3 w - -,31,450,13610,205984,6137712,93976246 -8/1N6/3p1P2/8/1K3kn1/r4b1R/7p/7n w - -,16,457,7886,229325,4137784,120870573 -6N1/8/4P3/P7/4k1P1/3b2np/8/K7 b - -,19,157,3050,29974,590738,6612011 -3k2nr/2p2p2/pr3qpp/1P1p2P1/Pn1P1P1P/1P2P3/B6R/R1BNKb2 b - -,38,932,35704,845787,32595213,772504410 -r1bk1b1r/pp1nqp2/3pp1pp/1Pp5/3P1nP1/B1N1Q3/P1PNP2P/1R2KB1R b - -,31,1110,35026,1298288,41428124,1570634703 -1N4Q1/1b6/5k2/r7/2Np2K1/3P4/8/QR6 w - -,46,788,34802,543802,24816322,391157061 -Rr6/2k1b3/2r5/p4p2/3Np2p/R1P5/5P1P/4KB2 b - -,42,1312,43312,1362200,41556046,1305894279 -6nr/1pq1b1k1/1N6/5Ppp/pp2B1P1/B1P4P/P2pK3/3R2NR b - -,33,1079,36461,1111699,38728983,1145149107 -r1Qk1bn1/7q/5np1/1B3p1r/p1p1PP1P/P1P5/1P1Bb2R/RN2K3 b Q -,3,74,2316,58257,1911810,49384091 -r1b1kb2/3pp1rp/1qp2ppn/pp1P4/2P1P1Q1/NP6/P3NPPP/R1B1KB1R b KQq -,33,1254,39174,1492710,46918985,1791482647 -3bn3/8/bp3n2/2kp1P1p/P1B1p3/1Pp4P/2R1K3/6NR w - -,18,374,7568,166280,3664889,84053370 -rnbqkb1r/1pp1pppp/p4n2/3p4/6P1/7P/PPPPPP1R/RNBQKBN1 w Qkq -,20,561,12563,362982,8912418,268736612 -rnbq3r/p2p3k/1p3p2/1Pbpp1pp/3P1N2/P1P4P/3BBK2/2R4R w - -,38,1140,39821,1181195,40238045,1198175669 -5b1r/8/pp1p1knp/1P2nqpP/P1bP1Pp1/1R2K3/2P2R1N/2Q2B2 b - -,37,1095,37966,1123386,40184620,1204207580 -5n2/7k/2B3p1/b3p2p/7P/8/4K3/3r4 b - -,29,399,10758,129116,3387710,40069030 -7Q/3b4/1N1k2p1/1P1p1p2/Ppn2P1P/3P3B/5R2/5K1N b - -,19,700,10601,391437,5647752,209114714 -1B3b2/r7/nP4k1/1P2P3/2P3pP/1N1bKBP1/2r5/4R2R b - -,41,1417,53310,1773162,64582330,2098351705 -4k3/1p6/5R1n/3r1Bp1/4b3/KRpp2P1/7P/6N1 w - -,33,715,22709,517555,16296345,387277245 -4k2R/5r2/2N1r3/1P1n2p1/8/K5p1/8/8 b - -,2,49,1451,30786,924634,18672728 -3k2N1/K7/p6r/p7/P3N3/8/8/8 b - -,17,236,3525,47870,705313,9503356 -r1b1kbr1/p1p2ppp/n2p4/1p2p1B1/P2PP2q/2NQ4/1PP2PPP/R4KNR b q -,34,1503,52112,2173716,76943929,3089090526 -2n5/3R3B/r1kb4/P3p2p/3P3p/2P1P3/4b3/B1K2N2 w - -,27,621,16508,392378,10462755,257103708 -k7/rr6/pQ4P1/Pp3p2/1P1p4/7b/R2K3B/8 b - -,13,389,5861,178865,3026574,93670101 -4r2r/Qppk1n1p/3b1p2/2B2n2/PP3P1q/2p1p1P1/R3P2P/3K1bR1 w - -,26,1225,32565,1425765,39316149,1650366795 -r1b2k2/bp1p1p1P/n1p2P1p/4B3/Pp6/1q2P3/2PP3P/RN2KBNR w KQ -,38,967,32474,835636,27121398,715986873 -1nbq1bn1/rp3k1r/p2p3p/N3pppP/P2B2P1/1P3N2/2PPPP2/1R1QKBR1 b - -,30,919,26226,818896,23771705,757311563 -1b3Bkr/3b3p/8/pB1pp1rP/2pP1Pp1/2p5/3R3B/2K5 b - -,23,634,14898,401320,9609432,254419150 -5N2/2k2Nr1/2nb4/8/3p4/8/3n4/1K6 w - -,5,180,2277,74905,936822,30084091 -1n4nr/P1p1p3/4brk1/bpP2pq1/4P1QP/N2B1KP1/P3pP1R/1R4N1 w - -,41,1297,47008,1586826,57385066,2018331606 -1n2Bbnr/p1pr1p1p/1p4b1/4k3/3pPpPq/2QP1K1P/P1P5/RNB3R1 b - -,43,1245,42934,1262476,41855785,1256932647 -8/4k3/3Q4/Rp1KP3/6bP/1pPN1p2/3N4/8 b - -,2,88,840,33424,359168,13958554 -2Q5/4n3/1P1k4/8/3P3P/8/3N4/5K2 b - -,7,207,1379,39049,293654,8373452 -8/3n1n1k/8/5P2/7B/2K2p2/3B4/8 w - -,21,334,6955,104429,2137005,32454709 -7r/k7/6p1/p2np2p/P3R2P/3p1P2/5K1R/4B3 w - -,20,489,10901,253382,5930176,133423825 -8/k1r2r2/4p1p1/p2n3p/PB5P/3p1P2/6R1/1R3K2 w - -,31,1016,27987,870559,23632324,715215121 -1n1rkb2/1q1b4/2Npp2r/1pp5/4P2p/nPPP4/4N1P1/1RBB1K1R b - -,28,924,27889,903728,28816272,929769807 -4rn2/6kp/2p4b/p5PP/K4p2/3RB3/8/8 w - -,24,418,9610,179900,4010307,78747217 -2b1kr2/1p1p1p1p/r1n2q1b/pQP1pPB1/P2p4/2N2P1N/1P2K1BP/R3R3 b - -,29,1283,36073,1557583,44511047,1874051619 -k2K4/8/8/6n1/6p1/8/4r3/8 b - -,24,81,1767,7499,165426,758525 -8/2p5/rp4P1/1pk2p1p/5Pb1/7N/2n3K1/1N6 w - -,13,333,3987,97718,1248438,30151131 -2b1kb1r/r4ppp/p1np4/QpP1pP1P/2P1P2q/N4K2/P2P4/R1B2nNR w k -,26,1108,24697,987483,24104807,930756437 -r3q2r/pb1k2bp/P1p2p1n/3pp1B1/2pPP3/1P4P1/1P2BP1P/1N1K2NR w - -,32,1080,33618,1122231,34439907,1141468182 -1n2kb1r/q2bp1p1/rp1p4/2p3Np/2PP1pn1/RPB1P1PB/3NKP2/7R b k -,33,1327,45452,1763826,61824871,2347042268 -6r1/5bk1/2nP3r/pP3pp1/P2R1PP1/b3PR2/5K2/8 w - -,21,932,19836,828013,18282820,730231719 -q7/1r6/3b1Pk1/8/1pP3P1/3KB3/B1n5/5R2 b - -,40,1153,46751,1169944,46363110,1097312081 -8/8/3N4/3k4/8/rP3P1p/4K2P/8 b - -,14,211,3281,43993,695750,8699083 -b1k3r1/8/p1prNRPP/Pp6/1P6/1Pn2B1P/8/1rB1K3 b - -,29,699,20227,522041,15161864,407377515 -rnbqkb1r/pp1pp2p/2p5/7n/P1B1p3/2P4P/1PQPN1pR/RNB1K3 w Q -,30,754,21512,605586,17999976,548056574 -k7/5N2/5b2/8/3b4/1K6/8/7R w - -,26,485,11336,224562,5054794,96986706 -8/1B2k1B1/1p2b2r/1N2p3/1P3P1P/p1R5/8/1N2Q1KR b - -,24,1207,26705,1337922,28770926,1435189780 -1bb4B/3kr3/7p/2P4P/2N1p3/Pn6/1R1P3N/4K3 w - -,25,595,15757,396433,10877234,282825534 -2b3n1/r1Npk2r/2n3p1/pPb2pp1/P2p1P2/2R3QP/3BP3/4KBNR w K -,36,1099,39742,1226960,44420699,1370663745 -1n2rk2/7p/rpb1p3/p4N2/P1P1pP1p/5n2/1b2PK2/2R2BBR w - -,25,908,21386,748529,17825825,615384595 -1nr2k2/1r6/1p5p/p7/b1P1pp1p/6N1/4PKB1/b4RnR w - -,20,866,18077,757102,17277798,708340503 -k3r3/r7/1P6/8/6p1/7n/2K5/8 b - -,33,281,7970,47817,1264909,7861559 -2N3k1/2r5/p4b2/p1p5/P7/N1n1KR2/8/7N w - -,21,590,12320,322627,7289145,184209016 -3k1b2/p4r2/1P6/P1p1pnpP/2P5/R4B1R/6N1/4K3 b - -,27,820,20973,646646,15953798,490598959 -r4b2/6r1/3k2pp/P2np3/4n1P1/R1PPP2P/4b1B1/1NB1K3 w - -,18,778,15302,631901,13282551,526146675 -8/5k2/p1np4/P2P4/P1p2B1Q/2N2K2/4Bb2/4R3 w - -,44,856,34793,576514,23869951,365095753 -4B1k1/8/4PR2/1p2BP1K/8/8/8/2n5 w - -,25,173,4241,31710,755566,5735474 -4k3/1B4bN/p2p4/P3p1P1/1Qr4p/N1P4P/4K3/1R5R b - -,20,865,15339,664721,11335694,492378687 -1N4B1/3r4/P5P1/7k/7P/3p4/K7/2b1NR2 w - -,26,551,15098,314975,8887862,184964843 -r7/1b1npkbr/p2p4/P1p4p/8/2q1P1PN/5PP1/RK1NQB1R w - -,23,1113,26355,1200408,31512423,1373120930 -8/1R3k2/3r4/2K5/5P1p/p5b1/8/8 b - -,7,129,2526,38143,787781,12229188 -r7/2b3r1/1N2P3/2p2R2/P3b2P/3kp3/1p1P4/3K4 w - -,22,941,17464,716501,13018294,514794489 -rnbqkb1r/pp1pp2p/2p2n2/5p2/P1B1P3/2P4P/1P1PN1pR/RNBQK3 b Q -,29,773,23043,642878,20140121,591320262 -r1b2knr/ppqp2bp/1N3pp1/2p1p3/1n4P1/4PP1P/PPPP4/R1BQKBNR w KQ -,29,822,22057,646865,17728122,536905476 -8/7k/2B1r3/6np/7p/3pP3/8/bR4K1 w - -,29,773,18823,512340,11623579,319382251 -4qk2/5Np1/pp4q1/2R2p2/P2KPP1p/1b5n/7P/3R4 b - -,45,1196,50893,1296781,53250853,1316185519 -8/8/8/3kP2P/8/1N6/8/5K2 w - -,13,70,872,5544,70038,444639 -r1bqkb1r/p1p1p1pp/np3p1n/3p4/5P2/N1P1P3/PP1P2PP/R1BQKBNR w KQkq -,33,846,27353,748878,24156020,696166402 -8/6Bp/7P/5k2/5P2/B1Rp2pr/N5K1/3R4 w - -,36,375,12704,142515,4896219,61211771 -b7/1k6/8/1B1p4/P2P2pp/1Q4n1/1K6/4r3 b - -,26,629,10768,280167,5329977,140883105 -5R2/3K4/1q6/P7/2b5/8/7k/8 w - -,19,639,8267,254153,3430874,102567800 -5k2/8/3P4/2P5/1K5R/6p1/4p3/4r3 b - -,12,231,3626,64660,1125148,19503793 -5bnr/1p3k2/5p2/1q2p1Qp/ppN3P1/B1P1pP1P/P2PK2R/4R1NB b - -,31,1027,28410,977428,27959885,984172584 -rn1k3r/p7/b1p3pp/qp3p2/1P2P1P1/1PNK1pnP/P2P1R2/R1B2B2 b - -,29,712,21506,507594,15787205,371508031 -8/1pp5/R5P1/1pk2p1p/5Pb1/r6N/2n5/1N3K2 b - -,30,513,13958,241839,6211778,111962279 -2bkq3/2n1p3/1rpp1Q1b/3P2pp/pBP3P1/PP2PN1P/3NKP1R/2R2B2 w - -,47,1401,61866,1846425,77925512,2354628674 -8/4k3/4B2R/4nP1K/1p3B2/8/8/8 b - -,13,317,3068,80659,750185,20893689 -r1b1kbnr/3p1ppp/2p1p3/pp6/1PN1P1n1/2N4P/P1PP2P1/R1BQ1BKR w kq -,31,973,30518,934905,30572808,926664333 -B2N4/5rk1/8/Pp1Rb2p/8/8/3K3B/8 w - -,25,696,18460,462251,13136553,309821162 -1nb4r/7k/1p1p1p1P/1P1p4/1p1p3N/5BB1/7K/1r4R1 w - -,25,625,16057,405253,10601169,275958404 -3r4/p1p2kp1/n6p/Pr2P1P1/2bbP3/1P3PN1/1RK1N2q/8 w - -,16,788,13461,664806,12309454,601669455 -r3k1r1/7p/1pn1p3/5np1/P3P1P1/5N1P/3R1KbR/1r6 w - -,26,1213,29587,1311047,30947814,1316433117 -r1bq1bn1/ppppp1p1/4k1r1/P4p1p/P3P3/B1P2N2/3P1PPP/RN1QKBR1 w Q -,32,609,19940,411315,13759924,305506978 -5n1k/8/2B3p1/4p2p/4r2P/8/3b1K2/8 b - -,26,329,8430,105470,2719485,33335069 -3r4/1k6/8/6b1/8/2K3p1/4B3/8 w - -,14,374,4894,129304,1679464,43521306 -8/8/PP4P1/4k3/3p1N2/r2P1b2/7R/3N2K1 b - -,23,648,13364,339492,6822959,170893147 -rnbqkbnr/1ppppppp/p7/8/P7/6P1/1PPPPP1P/RNBQKBNR b KQkq -,19,418,8957,217524,5212021,137514632 -8/8/2k5/4P2P/4K3/1N6/8/8 w - -,14,77,1096,7023,100330,545939 -1rb1k1r1/p3p1Bp/1N2P3/1npp2p1/QP3NP1/P2P1Pn1/7P/3R2KR w - -,39,1007,37939,986148,37670846,996287958 -r1q2r2/p1pk1pbp/b2p3n/Pp2p3/2QPP3/4B1PN/1PP2P1P/nN1K1B1R b - -,28,1131,30914,1205150,34989563,1332987941 -rN1N4/6k1/3P4/pp6/3KB1Pp/P7/1P1BP3/R7 b - -,10,484,4907,219949,2452707,103095581 -2r3k1/7r/2B5/1R4np/p6p/3pP3/8/b5K1 b - -,35,910,30972,751905,25946394,593779677 -r1bqkbn1/pppp1ppr/2n1p3/7p/1PP2B2/3P4/P3PPPP/RN1QKBNR b KQq -,33,1018,33408,1035570,34433604,1080120703 -rnk2br1/1b1pQ3/1P6/p3p1p1/1PPpPP2/7p/3N2PP/R1B1KB1R w - -,38,773,29688,664102,25490683,611194806 -8/B4bk1/8/8/1b3K2/4n1p1/6P1/8 b - -,33,347,9512,102094,2626193,29934125 -8/3k4/KbN5/8/7P/5p2/4r3/8 w - -,12,298,2930,71949,709342,16834420 -5bbr/3kB3/rp3q2/p4p1P/PpPpP3/3Q1N2/3P1PBP/RN2K2R b KQ e3,34,1251,41369,1511211,51194727,1871415270 -8/2Nr4/4N2k/p4p2/P1K2P2/6p1/8/8 w - -,15,244,3615,54174,787309,12040465 -1n2Bbnr/p1pr1p1p/1p4bq/4k3/3pPp2/2QP1pPP/P1P2K2/RNB3R1 w - -,34,958,31360,905244,29506509,873124359 -r1b1kb1r/pp1ppppp/n1p4n/6Q1/1q1PPP2/P2KB3/2P3PP/RN3BNR b q -,34,975,31314,903584,28723186,846528901 -3n4/5k2/4p1b1/4P2p/Qp5P/4P3/4K3/2N4B w - -,32,383,11223,165367,4819927,70923019 -r2k1bnr/pp2qpp1/B6p/2p1p2Q/P3p1bP/R1PP4/1P1K4/1NB3NR w - -,27,921,27477,900148,29060941,950900379 -8/8/1r6/k7/2K1b1p1/8/7p/8 b - -,34,119,3837,16111,505133,2336649 -3N3Q/3k4/n7/1r5p/2RB3P/8/8/3K4 w - -,39,660,24858,378844,14531262,221153850 -6k1/N1K5/p7/p4r2/P7/8/8/3N4 b - -,18,242,4291,55338,968459,12999292 -N1b2knr/pp1q2bp/5p2/2ppp1p1/6P1/2P1PP1P/PP1PK3/R1BQ1BNR w - -,22,619,14882,424156,10999869,317601757 -2k1nr2/5n2/8/8/8/K7/2B5/8 w - -,14,223,3095,59505,822291,17669581 -rnbq3r/3p4/pp3p1k/1Pbp3p/3p2PN/2P3K1/4B3/1R2B2R w - -,32,791,23584,629181,18816177,535826860 -2k5/5n2/8/K7/8/5r2/8/8 w - -,5,112,544,12632,60549,1409124 -4b3/4Qnk1/pp2p3/PPp1P2p/4B2P/4P3/3K4/4NN2 b - -,9,354,3920,144956,1833312,64555003 -8/5R2/R7/2p5/2P1K3/1q6/3k4/8 b - -,25,590,11959,273175,5550227,123533845 -7b/8/2b5/4k1P1/2P5/1p4p1/1NN1K3/3R4 b - -,19,519,8973,217051,3962701,91105149 -8/8/1P1k4/3n2Q1/3P3P/8/8/1N3K2 b - -,11,314,2717,78141,662236,18880227 -3r4/3npkbr/p2p4/PBp5/R3b1Pp/4P2N/5PP1/2KNQ2R b - -,46,1520,60699,2059136,77157509,2684615032 -5k2/pr1p2p1/1p1q3n/4NpP1/P1r1PP1p/1bp4B/1b5P/R4K1R b - -,45,1137,47207,1181707,49725062,1237072220 -3k4/3P4/8/2P4R/8/1K4p1/8/4b3 b - -,9,172,1860,35972,420229,8225570 -4rbkr/3P4/6p1/p2np2p/2p2P1P/P3P3/3Q1K1R/R1BN1BN1 w - -,44,1270,55076,1496424,64038350,1703290169 -4r3/1k6/6b1/p7/8/8/8/5K2 b - -,31,106,3110,17351,494254,2432685 -8/7k/3P4/1n2K2p/8/1P5p/3R4/8 b - -,13,243,3048,54743,672971,12219668 -2k4b/8/7N/3R4/3b4/3K1N2/8/8 b - -,18,501,8274,224617,3886648,104064430 -5b2/8/rn6/P2Pp3/2k1B1pp/2P1P3/1K2b3/B4N2 b - -,23,379,8948,143529,3601361,57854175 -r6k/1pr1n3/1P2p1p1/5p1p/5P1P/6b1/R2K4/7b b - -,39,468,16907,232909,8391395,114539108 -2bk1b1r/1p2qp2/rn1pp1pp/pPp5/3P1nP1/B1N2Q1P/P1PNP3/3RKB1R b - -,35,1170,40198,1408524,47880868,1737618090 -rn3kr1/pb2pp2/1N4pb/1PpP3p/5P2/P3P3/RP2K1Pn/2BQ2NR w - -,30,786,25203,691603,22930153,651489378 -8/1B5k/b6P/3R1b2/4n2K/8/8/8 w - -,17,368,7224,159937,3269799,70631657 -8/1Br1b1k1/8/6r1/4b3/2p5/1n6/3n1K2 b - -,51,386,18508,161425,7490014,70141950 -1B6/5Bk1/4P2R/2n2PK1/1p6/8/8/8 b - -,10,220,1565,38608,294035,7295127 -rn2kb1r/2p1pp1p/6p1/pp1p1q2/1P1Pn1b1/PNP2Q2/4NP1P/R1B1KB1R w q -,32,1271,43219,1745508,60493338,2452890113 -rnbq1kn1/1pQp3r/p7/1N3pNp/4p3/2bPPP2/PPPB2PP/1R1K1B1R w - -,48,1532,70833,2220165,99378757,3137913085 -3rn3/1k4n1/8/p3pN1p/2B4r/5K2/1b6/1N4B1 w - -,34,1109,30958,1024833,27020333,906505699 -4B3/8/k3p3/4P2p/4P2P/8/1K5N/8 w - -,18,76,1294,7230,118773,617253 -Rn5Q/p1k5/2pqP3/1pb5/1P4p1/2P5/2KRB1P1/8 w - -,40,870,33345,794114,30079237,743767979 -8/8/P3R1n1/k6n/1p6/7P/2B3KR/6N1 b - -,12,274,3397,88818,1182959,32311988 -4r2r/4p3/b4P1k/2p2P2/7P/1q4Pp/R6K/6R1 w - -,25,1091,25284,1017732,23915442,938831722 -2bQ4/5n1k/2P2r2/p2p1p2/PN3PPp/1P5P/5n2/R1K5 b - -,27,711,16910,458188,10680416,299229872 -2k4b/2P5/2Q1p1p1/6rp/2RN3P/1R4B1/8/3Kn3 w - -,51,754,36186,601422,27449960,490780140 -3k4/8/2B5/2P5/4p3/2K1N3/7b/8 b - -,10,213,2332,47793,551787,11049823 -6R1/rpp5/1k4P1/1p3p1p/5P2/P4P1b/n2K4/1N2n1N1 w - -,17,384,6862,155066,2917966,65932630 -2k2r2/6p1/8/r3P1pP/1P1P4/2n5/3K4/6N1 w - -,14,494,6047,200017,2462141,77962826 -5k2/n6B/p2p4/P2P4/2p4Q/P3K2N/1b5R/4B3 b - -,16,621,8217,320922,4254441,166616016 -8/8/P7/2k4n/1pR4n/1B5P/3R4/3K2N1 b - -,2,72,791,28088,351975,12367910 -1r6/3k1N2/1p4R1/1P3p1K/P7/8/1bB5/4b3 w - -,28,738,18651,479345,11904961,303257797 -1nbq1bnr/rp3k2/p2p3p/4pppP/P1NB4/1P3N2/2PPPPP1/1R1QKBR1 w - -,32,847,26351,708753,22018219,613011023 -6B1/6k1/5r2/6bn/b1np3r/2p5/2R5/3K4 b - -,47,337,15183,184265,8213297,115147789 -8/6P1/p2b3p/P3k2P/5RP1/1b6/3pK3/R7 b - -,23,619,13422,349567,7539860,194958030 -1b6/5Pr1/8/2P3k1/1p4P1/8/5K2/1BR5 w - -,27,470,12107,218506,5840348,109124497 -8/1B3n1k/4p1b1/1p2P2p/p6P/Q2NP3/8/4K3 w - -,33,474,15372,235513,7375537,118957350 -r7/2p1r1P1/P3kn1p/P2p4/3Pp1bP/1P1nKR2/1B3R2/1B6 w - -,27,895,25390,824121,23819309,759310245 -8/Q1b5/1k2P3/8/8/1K3B2/6P1/8 b - -,2,53,499,12741,125032,3222526 -rnq2Bnr/3k3p/1p2p1p1/8/P4bP1/2Q2b1P/3pPKB1/5RNR w - -,44,1708,62677,2499457,88464305,3593737986 -8/3K3b/P7/8/8/8/1R6/4k3 w - -,23,213,4221,48954,940476,11431734 -8/2K2k2/p1N5/p7/P7/8/5N2/2r5 w - -,13,237,3691,62833,1002950,17046479 -2kr4/6p1/6p1/r6P/1P1PP3/8/4N3/3nK1n1 w - -,14,453,5864,183278,2284288,70143890 -kb6/8/8/6Q1/8/3K4/6PQ/5B2 w - -,46,336,13740,129773,5380714,50554558 -5r2/k1r5/4p1p1/p2n3p/PB5P/3p1P2/6R1/1R3K2 b - -,41,1154,40442,1113446,35962735,978764157 -r6r/pb1k4/P1p4p/3Pb1B1/1PBP1q2/6P1/1P1NKn1P/7R w - -,34,1550,46853,2033933,59910039,2516772455 -3B1k2/rp6/P7/R2pp1K1/8/6Pr/1p5P/nN2N1b1 w - -,24,614,14400,401456,9893959,291058483 -rnbqkb1r/pppppppp/7n/8/3PP3/8/PPP2PPP/RNBQKBNR b KQkq -,20,759,16820,635081,15475268,582864927 -4r2r/Qppk1n1p/3b1p1n/2B5/P2ppP1q/1P4P1/R3P2P/1N2KbR1 w - -,32,1360,43132,1764470,56499778,2253558504 -7K/8/3r3P/8/3n3k/2p5/8/1r6 w - -,4,152,588,22003,109900,3840053 -rnbqkbnr/1ppppppp/8/p7/3P4/8/PPPNPPPP/R1BQKBNR b KQkq -,21,483,11325,286109,7327437,201919255 -1rbk1r2/p1p1p2p/1p5b/QnBpPnp1/1P3pP1/P2PqP2/1N2N2P/1R2K2R w - -,26,988,24564,923250,24576001,914423102 -8/4k3/8/3p1p2/p4Qb1/6P1/3B1bP1/3R1K2 b - -,22,572,9059,271545,4331978,133168347 -1nnBk3/1b6/8/P1p5/2PpP1KN/1p1P4/8/6b1 b - -,20,345,7300,122572,2681252,44981053 -1n4k1/1b2r2p/rpP1p3/p4Nb1/P1P1pP1p/5n2/1Q2PK2/3R1BBR b - -,30,1412,40513,1738773,51579746,2095999046 -4B1r1/k7/4n3/p3p3/3r2p1/6B1/1b2K3/3N4 b - -,36,695,24701,478266,16780399,331091023 -3N4/1n2r1kb/8/8/2K3p1/4B1P1/8/7R b - -,24,631,14401,369040,8698428,216893641 -6q1/2k4r/4pnp1/p6p/P1pP3P/B3rPK1/3R3R/5B2 b - -,39,1104,41157,1083538,39680758,1022718624 -rnb1kb1r/p2ppp1p/1q3n2/1pp5/5p2/PP1P4/2PNPPPP/RN1QKB1R w KQkq -,19,612,12915,430332,9900651,338540975 -4k3/1NB3r1/3r1b2/3b4/p1Pp1p2/P2P4/4K3/6NR w - -,25,868,20176,667823,16090585,516406339 -1n2kb1r/1q2p1p1/rp1p4/B1p3Np/b1PP1pn1/RP2PNPB/5P2/3K3R b k -,39,1291,48913,1674969,62030941,2175083444 -Rr6/2k1b3/7r/p4p2/4p2p/1RP5/4NP1P/4KB2 w - -,25,874,24789,772182,22969636,671729388 -b1k1r3/7p/2n1q3/R1Pp4/P7/3p4/2NP2Kn/2B5 w - -,17,659,9862,385117,5963777,228882182 -Q1k4b/2P5/4p1p1/6rp/2RN3P/1R4B1/8/3Kn3 b - -,1,62,1009,56768,1022834,53311049 -3rkb1r/p4p1Q/3p1np1/1pp3P1/P2pP3/R6b/1PKN2qP/2B3NR w k -,31,1249,35705,1428249,41057490,1627327131 -3k4/pr4Q1/b2p3p/P4P1P/1bB5/3p2pR/2PR2P1/3K4 b - -,19,695,13120,436325,8762556,283241228 -2bq1b2/3kp3/nrpp1n1p/3P1pp1/pBP3P1/PP1QP2P/3NKP2/1R3BNR b - -,29,869,24309,776907,22423608,748397890 -k2n4/3N4/1R6/6p1/1K6/2pp4/7P/8 b - -,8,176,1597,36945,398442,8937068 -3N4/8/3p1P1R/1b6/5kn1/6n1/1K5p/8 b - -,31,598,17179,323052,9022364,173407733 -rnb1k3/p3n2R/Pqppp3/1p1NPp2/1P4p1/3P4/2PRN1P1/2K1bBQ1 b q -,31,1086,28714,984312,25986414,881452187 -8/r7/1kN5/8/p2R1K2/Pb1P4/3r4/4N3 w - -,26,791,18824,529960,12387296,341273390 -1Nk3nQ/7p/4Pppb/7P/2p1P1P1/8/b2r2q1/1RB1K1R1 w - -,24,792,17863,604921,15387352,522746399 -rnbqkbnr/pp2p1pp/2p5/3p1p2/2P5/1P6/PB1PPPPP/RN1QKBNR w KQkq -,28,754,21381,611204,17818988,533883182 -3k4/8/5P2/8/2r5/6N1/5K2/4B3 w - -,17,286,4683,74825,1298019,20780956 -B6k/5n2/4p3/pp2P2p/7P/Q3P3/2b2K2/4N3 w - -,32,564,17359,290336,8747604,143291215 -2k5/8/4p3/4P2p/1KB1P2P/5N2/8/8 b - -,5,110,628,12689,62142,1186863 -B7/2r1b3/7k/6r1/4b3/2p5/1n3n2/5K2 w - -,7,354,3387,162057,1666757,77380490 -rnb3r1/p2p1pk1/1p6/2b3pp/2P2qP1/1PNPP2n/PR1K3P/1QN1BR2 w - -,27,1227,32047,1384351,37485619,1575006119 -4nr2/2k2n2/6B1/8/K7/8/8/8 b - -,19,248,5180,68596,1566508,20477382 -4q3/4k1r1/p3pnpB/7p/P1p1P2P/1r3P1B/R2PK3/2B4R w - -,29,1166,33609,1279945,37407121,1380962952 -bk6/b7/7p/B1P4P/4p1r1/P7/7N/3K4 b - -,17,271,5302,83541,1773142,28180324 -3N4/1r1k4/n7/4Q2p/3B3P/2R5/8/3K4 b - -,14,658,8238,370565,5176127,224271664 -5knr/3n3p/p7/pNpP4/P2b2p1/2rRPP2/1q3N1P/2B1KBR1 b - -,39,1104,41746,1164215,43106139,1204287038 -4k3/4r2p/2b4P/3p4/p1pb1B2/6p1/2B3Rr/3K4 b - -,41,969,35700,854901,30354789,729809938 -5Br1/3k3p/7P/2RpR1p1/3r1P1P/2Np4/6K1/2B5 b - -,14,531,9019,339812,6534927,239935318 -3r4/p1p3p1/n1r1P1kP/P4b2/2Rb2P1/1P6/3KN3/7N b - -,39,754,27560,563613,20412337,435782921 -r2q1bnr/4pk2/4Qp1p/pppp1b1P/PPP3p1/N1N2PP1/2RP2B1/2B1K2R b K -,4,164,4172,166383,4495291,175887407 -8/R7/6n1/8/1k6/8/3b4/1K6 b - -,18,316,5498,87471,1522507,24313156 -2n5/3Rb2B/r1k5/P3p1pp/3P3P/2P1P3/3Kb3/B4N2 b - -,27,701,16816,442872,10918832,288843367 -5r2/k7/4p1p1/p6p/P6P/2rpnP2/5KR1/1R2B3 b - -,34,675,21060,466535,14067016,330587142 -8/8/b1kb4/2b3P1/8/1p5N/3K4/N3R3 w - -,22,629,12286,352023,6882355,195631658 -8/4k3/2r1Br2/Pp4Q1/3N4/1p5K/1b6/8 b - -,21,828,18802,659156,16217176,540181698 -2k5/8/8/4P2P/8/1N2K3/8/8 b - -,5,80,497,7563,40772,603047 -7k/2N5/2n4p/Pp1p3P/P2pPR1B/7R/b4PP1/3K4 w - -,38,604,20763,306280,10132534,148451806 -1k6/5n2/1q6/1QPPpNr1/1KP2R2/5Ppp/8/6R1 w - -,29,575,16879,368728,11310748,259659823 -2bkq2Q/2n1p3/1r1p3b/2pP2pp/pBP3P1/PP2PN1P/3NKP1R/2R2B2 b - -,29,1105,31573,1166929,33886402,1237909944 -8/7r/7k/8/n3q3/6K1/2b5/2R2B2 w - -,15,638,9723,411182,7025148,293718834 -r1bqk1nr/p2p3p/n6b/p1pPpP2/6p1/P7/1PP1PP1P/RNB1KBNR w KQkq -,26,706,18003,517533,13350014,401386133 -b2r2nr/3p4/2n3pb/p1p2kP1/2p2N2/P4P2/4P2P/3K1B1R b - -,24,467,11425,217168,5645436,106891906 -8/8/8/1pk5/8/4n1pr/8/1K6 b - -,24,97,2383,10290,259078,1139650 -7k/1B6/7P/6RK/b7/8/8/5n2 w - -,26,301,5980,77333,1600374,21479746 -1n6/2B2nK1/2k5/2p5/2Pp4/8/8/5b2 b - -,17,236,4156,50780,934451,10908209 -6n1/5r2/r2k1p1p/p1b3BP/P5P1/3P1P2/2N3BK/6R1 b - -,31,830,24235,631414,17893578,462311919 -1B6/1r4k1/1bB5/PpR5/4KN1p/8/8/8 w - -,36,674,22117,422047,13597931,265917442 -1Q3k2/8/8/p2p1p2/R4p2/5bP1/3B1bP1/5K2 b - -,3,117,1994,67254,1134471,37299089 -b4k2/6RB/1P6/p5P1/P3Pb2/8/2K2p2/8 b - -,20,377,6861,123897,2416083,44230889 -r1b1kbnr/2q1p3/5p1p/ppppP1p1/P1Pn3P/NPN2PP1/R2PQ3/2B1KB1R b Kkq -,41,1436,56757,2010775,76722656,2761488752 -2Bk4/2N4N/1Q6/P2pb1P1/1R5p/2r1p2P/4K1R1/8 b - -,21,964,17116,771774,13423537,593673328 -1n6/rb2B3/1P4kb/pP2pr2/2P1P1p1/1N1K2P1/6BP/1R5R b - -,32,1146,35904,1241163,39080424,1317789201 -3kr3/3r3p/p6P/npp1p3/2Pp2K1/P6Q/RP2Nb2/N4B2 w - -,28,793,21955,626986,18007859,518182314 -5N2/4N3/3p4/5q2/5k2/3b2R1/K4n2/8 w - -,25,671,13911,397280,8208446,240308119 -r1b1kbnr/1p1p3p/6p1/pqp2p2/1n2PB2/P7/2PQKPPP/R4BNR w kq -,6,210,7996,276805,10553681,367158021 -8/kr6/8/3B4/3K3b/6p1/8/8 b - -,22,374,7732,113903,2505408,34223873 -8/p1P4k/P7/2P5/4r1R1/1P4K1/8/5r2 b - -,29,479,11506,214299,4982961,98760822 -n3k1n1/rB6/2p2pr1/1PBPp3/5P1P/2pP4/6q1/1NR1KQ1R w K -,38,1533,49829,1957006,64904252,2502092167 -3R4/4k1p1/8/8/b3KP2/N5Pn/q7/8 b - -,33,581,17490,292052,8809285,144453469 -4b3/1k6/p7/Pr4B1/8/3p4/8/1R1K4 w - -,18,293,4818,92348,1607459,32566540 -B4k2/8/1P4P1/p4r2/8/2K5/8/1R6 b - -,17,400,6672,155485,2546499,59873029 -bn3R1r/3k3p/2p5/p1Pp2q1/P7/2Np4/3P3n/2B3nK b - -,33,718,22469,430517,13693717,248924270 -b7/b4N2/8/2k4P/P3p3/3r4/5K2/8 b - -,26,284,6992,74859,1812526,18948245 -4k1b1/1Np3r1/6r1/p5b1/pBPp1p2/P2P1P1N/6q1/4K2R b - -,40,624,23920,398832,15261307,276616126 -8/4k2N/P5P1/3p4/2Q3B1/1R2pNpP/4K3/2r5 b - -,16,638,8655,336787,4467029,171511165 -2k5/1r6/1p3R2/1P3p2/P6K/3Bpn2/1b6/R3N3 w - -,4,108,2906,69404,1906508,45643963 -2b1k1r1/p5b1/B2ppn2/6p1/Pr1PP1Pp/R1p2N1P/2P5/1N1QBK1R b - -,31,1078,32857,1134111,34604317,1197491737 -7k/8/1p3n1P/1P1p1bKb/8/5B2/3Rr3/8 w - -,20,682,12859,394545,7505368,220005662 -6k1/4b3/8/7b/4K3/B5p1/6P1/3n4 b - -,24,248,5631,60414,1361537,15117256 -r1b3rk/1p6/n7/Bqbpp1p1/P1p3Qp/4n1PK/2PN3P/RN3R2 b - -,45,1369,61162,1868162,82296949,2570806002 -3k4/8/5P2/7r/8/5KN1/8/4B3 b - -,18,313,5054,90079,1449189,26174614 -2b2bn1/r2pqp1r/4pkp1/ppp3Np/1nPP4/P4PP1/3RP2P/2Q1KBNR b K -,31,926,26997,837936,24781881,791039985 -8/8/4k3/8/1p1p4/1p6/8/5B1K b - -,10,97,883,9837,91520,1087866 -8/k7/4P3/8/3b4/5B2/2KQ2P1/8 b - -,15,519,5770,196825,2110566,70943551 -8/4N3/4P3/P4nP1/4k3/3b3p/1K6/8 w - -,14,284,3738,74224,951209,19102348 -3knR2/pr6/PP2B3/2p4P/1NP1p1p1/1R6/8/4K3 w - -,39,494,18018,246709,8624093,126490721 -r1N2b2/nb2p1kr/6p1/pPpP1p2/1P1N1P1p/P3P2Q/R4KPn/2B3R1 w - -,38,1018,37563,1034598,38423021,1088696476 -8/1Q1P4/p3k3/P3p3/n1p5/2N1bK2/8/3R1B2 b - -,20,846,13324,549704,8381257,340064471 -2R4r/1k6/1p2R3/pPb1pp2/B7/3N2K1/P7/1n6 w - -,33,767,22077,499418,14317426,321236312 -2b4k/R7/5PP1/2p4P/5K2/8/8/8 b - -,9,194,1757,36352,332795,6691712 -r1b2bQ1/1p1ppk1p/7n/p5p1/2P1pP2/6PN/1B1K3P/R4B1R b - -,3,111,2063,71653,1462366,50791369 -6B1/5rk1/8/6bn/b1np3r/2p5/2R1K3/8 w - -,10,497,5668,260997,3625616,159320602 -5kr1/4q1nb/1pB1p1p1/4B2P/p4P1P/N2R4/1P1N1Q2/5K1R w - -,60,1264,72801,1544002,83117955,1881922049 -b2r2nr/n2p4/6pb/ppp2kp1/2P2N1P/P4P2/3KP2P/5B1R w - -,24,587,12786,334303,7097913,195577428 -8/7N/1k6/1P3R2/6nP/1Kb5/8/8 w - -,22,441,9138,165417,3407575,58996323 -8/2PkP1b1/8/1p1pP3/1p3r2/3K4/3n4/7q w - -,13,391,4619,143831,1790560,57560235 -5n1k/8/2B3p1/4p2p/1b5P/8/6K1/8 b - -,16,266,4386,65349,1100942,15133848 -1n1rkb1r/1p1bN3/1q1pp2p/2p3p1/1nQ1p2P/P1PP1P2/1P2N1P1/R1BB1K1R b - -,33,1526,50921,2304898,77407932,3430521627 -2r5/5k1B/p4n2/prpP2P1/P1nN4/2N4P/1b6/4KR2 b - -,29,974,27352,875512,25669732,798517866 -6k1/rp6/n4B2/P1bppr2/8/1p4PK/6NP/RN6 b - -,29,559,17012,358440,11237335,255267672 -2N4R/5k2/p7/p1K5/P1p5/N1n3N1/8/8 b - -,12,313,3254,92282,928576,26396444 -rnbqkb1r/pppppnpp/5p2/8/5PP1/2N5/PPPPP2P/R1BQKBNR w KQkq -,23,503,12617,292864,7820901,193299666 -r1bnk1nr/p3p3/1q1p1p2/2p3Pp/pP3pP1/2PP1N1B/4PP1R/R1QK4 w kq -,33,1224,41033,1509358,51196131,1882582957 -8/n2r4/2kb1pRp/7P/P4N2/3P4/3B4/5K2 w - -,27,615,16953,398144,10910810,256163968 -r1k4r/p4pQ1/3p2pb/1pp3P1/P2p4/2nR2Nb/1PK4P/2B4R w - -,36,1128,42509,1332516,50976527,1601107553 -rnbqkb1r/pppp1ppp/8/4pn2/P2PP3/8/1PP2PPP/RNBQKBNR w KQkq -,40,1341,51966,1729845,66597786,2232624013 -4kb1r/4p1pp/2p2p2/p3PP1n/2Ppq3/2N4N/1rR2KnP/5BR1 b - -,40,709,27656,549916,20863426,461222087 -8/4k3/8/4n2P/3P4/8/4K3/N7 w - -,11,165,1808,23747,265907,3267533 -8/8/2P5/1K6/6k1/8/7p/8 w - -,8,96,762,9819,83049,1249615 -6k1/8/2n1K2P/1B6/8/8/8/4R3 b - -,11,249,2057,50947,401549,9868094 -5k2/1Nr5/p4b2/p1p5/P7/N4Rn1/4K3/7N w - -,8,157,3541,77964,1845652,42312066 -rn2kb1r/1b2p1pp/p1p4n/3p2B1/2P5/3Q3B/PP1KPP1q/RN4NR w kq -,46,1185,51200,1402699,58563889,1678504478 -2k5/1p2B1bp/3pp2n/3Q1p1P/2pP4/r6R/2K1P1B1/6R1 w - -,46,1229,52396,1321044,56147832,1382861131 -8/5k2/7B/2K1P1P1/ppR5/P4B1p/1P6/8 w - -,33,237,7545,49951,1574166,11060971 -8/7r/q4k2/p3p3/PP1r2Pp/1KnPpp2/1R1N2B1/1R4N1 b - -,52,1176,54270,1298865,58692925,1474607869 -2K5/6b1/k7/8/7P/8/b7/R7 b - -,13,158,2711,40879,777067,12411838 -r5nr/1b1p1p2/2nqNk1b/pppP2p1/2P4P/P4P1B/1Q1RPK1P/6NR b - -,5,199,6885,257913,9115508,333059528 -n2q1b2/3k4/3pN3/1r1P1bp1/pPP1PPPp/7P/p1N1K1B1/R5R1 b - -,30,1155,33718,1183963,35762316,1181413280 -3k4/4n3/8/8/7N/1K1p2N1/8/8 w - -,17,188,3080,36928,593492,7513269 -1q1k1bnr/pr4p1/n1ppQ3/P6p/1p2P2P/1P1P1PPB/R1P2K2/1N4NR w - -,39,764,29361,639090,23932733,567100483 -rn1qk1r1/p2pn3/b1pb1ppp/1p1Qp3/4P1P1/2P4P/PPKPNP1R/R1B2B2 w q -,35,758,26038,610160,20655740,515925466 -1r5r/5b2/2nP1k2/pP3pp1/P2R1PP1/b3PR2/8/4K2Q w - -,32,1317,41312,1582632,49801530,1826282037 -8/4k3/8/1p1KP3/1N5P/2P2p2/Rp1N4/8 w - -,25,237,6355,72089,1893467,25106116 -rnbqkbr1/pp2pppp/B1p5/3p4/2PP1Pn1/P3P3/1P4PP/RNBQK1NR b KQq -,31,924,29108,897464,28761568,909917331 -rnbqkbnr/pp6/8/3pBp1p/PpP5/7N/3PPPPP/RN1QKB1R b KQkq -,36,1167,42290,1365627,50088360,1654466908 -3r4/k7/8/6b1/8/2K3p1/8/5B2 b - -,27,299,7839,94877,2416994,30215030 -r2qkb1r/1ppbpppp/2n2n2/p7/1P1p2P1/3PP2P/PBP2PBR/RN1QK1N1 b Qkq -,31,1082,34916,1187320,39679438,1333216487 -5n1k/8/6p1/4p2p/B6P/8/4K3/3rb3 w - -,11,253,2679,65038,717895,17872893 -8/8/8/1p1N4/2k5/8/4K3/8 w - -,15,84,1093,7180,88622,580280 -5r1B/R1p5/Pn2P1p1/8/6k1/1PrN4/4K3/b6N b - -,36,843,26784,627264,20006111,486973532 -1k6/8/5pP1/p1p5/P1P3K1/1P6/N4r2/R3R3 b - -,17,369,6026,135045,2194131,51054861 -3rkb2/p7/n1n5/3b4/pP1p4/2QN1p2/5P1K/BR4n1 w - -,29,890,25435,800524,23734841,751210082 -k7/8/1b5P/rb6/4N3/8/4p3/4K3 b - -,24,228,6180,57585,1676109,15710497 -8/8/1k4pr/7p/PB2RP1P/3p4/6KR/8 b - -,9,262,2903,88836,1155896,35466454 -1rbqkbr1/p2p3n/1P2p3/6p1/P2P2Pp/2p4P/2P1P3/RNBQKBNR w K -,23,650,16179,477632,12819578,395274429 -8/1B5k/7P/1b3R2/4n3/7K/8/8 b - -,21,443,8022,174463,2915527,64810601 -rnbqkbnr/1p1ppp1p/p7/2p3p1/PP3PP1/8/2PPP2P/RNBQKBNR b KQkq -,23,549,13677,352527,9476516,259948029 -4R3/5k2/8/2PP4/1K2p3/6p1/5rp1/8 w - -,20,350,6200,116104,1986787,39612921 -1r2kbnr/pb2ppp1/np6/2pP4/P2PB2P/q7/NP3PP1/R1BQ1KNR w k -,42,1502,61527,2289415,93127715,3552100253 -3nkN2/1r6/B7/8/PQ1P4/1P3P1p/K1p4P/6R1 b - -,19,750,14436,542643,10898560,399028375 -8/5b2/P2b4/1k2p3/8/2P1n1Np/8/1K6 w - -,11,338,3510,99518,1095683,29595829 -r1b1kb1Q/1p1pp2p/7n/p4pp1/1qP2P2/6PN/1B1NP2P/R3KB1R b KQq -,28,955,27714,954814,28357730,1000475263 -7r/7p/2bb2kP/p2pp1r1/B1pP1Pp1/2p5/6RB/3K4 w - -,23,670,14168,411562,8603213,250384985 -2k4b/P1P5/2N1p1p1/3P2rp/R4B1P/3b4/2nK1R2/5r2 w - -,35,1177,38452,1266129,41360964,1342908977 -2r4r/Qppk1n1p/3b1p2/2B2n2/PP3P1q/2p1p1P1/3RP2P/4KbR1 b - -,43,1091,44720,1157370,46101993,1221409842 -rn2bknr/4b3/3pP2p/8/pP2PPpP/p1R5/2KB1P2/1NN4R w - -,32,732,23113,578528,18047012,482030905 -6R1/1r5k/3Q3b/3Np2p/Pp2PP1P/5N2/5K2/8 w - -,54,730,35710,496846,22624563,325999995 -1nbqk2b/3ppp1r/6p1/ppp4p/PP2B3/B3P1PP/3P1P2/RN1K2NR b - -,28,830,24268,711025,21574638,634060306 -6b1/k7/2KbR3/8/7P/8/8/8 b - -,17,257,4183,63237,1054427,16625692 -1n6/2N3k1/7p/Pp1p3P/P2pPR1B/1R6/b4PP1/3K4 b - -,12,435,5092,177526,2233663,75472216 -8/1k2N3/P3Q3/1p3r2/4r3/1p5K/1b6/8 b - -,4,103,2802,68646,1831577,45358321 -2k2brn/1b6/2pr3p/P1BppPp1/p1P3P1/N4QP1/R2PB3/1N4KR w - -,40,843,34714,772443,32129275,745509861 -1rbk3r/1p1p3Q/p1Bb4/1q1nP2p/5p1P/1PP1PP2/P2K2P1/RN4NR w - -,36,1176,39321,1282383,42286497,1383686256 -1nb1qbn1/r4k1r/pp1p3p/N4ppP/P5P1/1P6/2PPPPRN/1R1QKB2 w - -,20,711,15565,539154,12970759,446414621 -r1b1kbr1/p1p2ppp/n2p4/1N2p1B1/P2PP3/3Q4/1PP2PP1/R4KNq w q -,44,1240,49371,1487011,57699450,1822944736 -1n3b1r/4k2p/3Q3n/ppp4b/3pP1R1/3P4/P1P1K2B/RN6 b - -,2,74,1033,36645,626548,22267426 -8/4k3/2n1B2R/5P1K/8/1p6/8/2B5 w - -,22,227,5825,56313,1536554,15502068 -2k4r/6n1/1K6/8/8/8/8/8 b - -,18,102,1988,9589,200287,1045463 -3n1N2/4k3/B7/1r6/P2P4/1Pp2P1p/K6P/3Q1R2 b - -,22,610,11587,348216,6598553,209258288 -8/2Pk4/5bp1/2R3rp/3pQ2P/1nR3B1/8/3K4 b - -,19,932,15787,691515,12454234,520490019 -1k6/8/5pP1/p1p1r3/PPP4K/8/N7/R7 w - -,16,299,5000,91788,1651928,29650643 -5Nr1/5N2/1kn5/8/3p4/6b1/8/3K1n2 w - -,13,404,5285,166510,2220028,70049116 -3r4/3npk2/p2pr3/P1p5/R3b1Pp/2b1P2N/B4PP1/2KN2QR b - -,43,947,34818,880096,31212710,865380450 -8/B1R5/7P/b4Q2/3P4/k7/8/1K6 w - -,45,354,14132,112479,4308781,37197085 -rn2qbr1/N1pk1b2/Qp2p3/5Ppp/B2PPP2/2p2N1P/PP6/1RB1KR2 b - -,6,251,6606,275475,7639318,316602336 -1rb1k2r/1p1p2Qp/p1p2n2/qB2p3/3P1p1P/bPPKP3/P4PP1/RN4NR w k -,38,1102,38972,1132105,40121214,1173373282 -5b2/r1B5/nP6/pP2P1k1/2P3p1/1N1bK1P1/3r2BP/1R5R b - -,35,1218,41582,1380827,46927631,1529513205 -r1b1k2r/p1p1p2p/Qpqn3b/1B1pP1p1/1P1n1pP1/3P1P2/PNPB3P/R3K1NR w k -,33,1017,31699,1016399,32160991,1074059093 -3q4/3k4/1n1pN2b/1r1P1bp1/pPP2PPp/p3P2P/4K3/R3NBR1 b - -,33,899,28647,777314,25288947,685512696 -1nK5/4B3/2k5/2p5/2b5/8/3p4/8 b - -,20,166,3462,32486,721530,7205325 -r2k1bnr/pp3p2/B3q2p/1Pp1p1pQ/P5bP/R1PPp3/8/1NB1K1NR w - -,24,967,27206,1039444,32001154,1184886448 -1k6/6N1/Pr6/1p4b1/4r3/1p6/6K1/8 w - -,13,442,4515,146431,1513310,48534407 -5b1r/4k3/rp2bq2/p4p1P/PpPpP3/1Q3N2/3P1PBP/RN2K2R w KQ -,33,972,31822,1044616,34070549,1183586373 -r1b1kbnr/1pq3p1/2npp2p/p1p2p2/4P2P/2PP1P1N/PP1N2P1/R1BQKB1R w Qkq -,29,1031,30910,1053636,32507370,1091601083 -6k1/rp6/n4B1r/P1bpp3/6K1/1p4P1/6NP/RN6 w - -,22,687,15366,481170,11439721,360621927 -r1bqkbnr/p1p2p1p/4p1p1/1p1p2N1/4P1PP/3B4/P1nPKP2/RNBQ3R b kq -,39,1152,42968,1303940,48259807,1511587113 -1b6/3b2r1/rpk3N1/p4p2/PpP1P3/2RB3P/3P2R1/1N3K2 b - -,26,713,18454,501921,13608909,372219074 -r1bqkb1r/p1ppp1pp/1pn4n/4Pp2/6P1/5P2/PPPPQ2P/RNB1KBNR b KQkq -,23,682,16698,520659,13382763,430880874 -rnbqkbnr/ppppp2p/5p2/6p1/2B1P3/5P1P/PPPPN1P1/RNBQK2R b KQ -,19,623,12780,416595,9401127,305539216 -3k1r2/3r3p/p6P/1pp1p1K1/1Pnp4/P6Q/2R1N3/N4Bb1 w - -,34,1176,36588,1210914,38768193,1240692212 -1k6/b3n3/5P2/3b4/3pNbPp/3K2RP/8/1B6 b - -,31,494,14774,261280,7396506,141732967 -8/k7/8/3K4/4pb2/1BN3p1/2r5/8 w - -,17,416,6074,142909,2295649,53568961 -1b6/8/2k4p/P4prP/2n5/2BP4/4N3/4KR2 b - -,31,736,20448,480327,12912487,301569752 -4k2r/6Rp/5n2/p2p1P2/2P1N3/3K3N/2Rp3P/2b4r w - -,37,869,26165,652712,19022519,498008372 -1rb3r1/p2p1pk1/1N6/4q3/PnP2pPp/1P1PP3/1R1K3P/1QN1B1n1 b - -,52,1066,52243,1172276,54690076,1316817858 -rnb1qb1r/2pppk2/pp6/5ppp/P1PP4/4P3/NP3PPP/RQnK1BNR b - -,29,835,24658,731446,22430598,686183791 -6R1/3k3r/p2p1P1p/P6P/1b6/1b1p4/3R2P1/5K2 w - -,25,539,12387,275076,6132952,140127954 -8/3n4/1k2R3/6p1/K7/2p5/3p3P/8 b - -,4,82,1284,20676,345163,5648862 -1r5k/5b2/1p4RP/1Pnp1p2/6NB/1p1p3K/6B1/8 b - -,23,606,13240,352364,7945494,216415511 -1r1k1b2/n7/p2p2Q1/P1pP4/8/P2K1Bp1/3B4/R5NR b - -,21,972,18370,838475,16058130,721737772 -1r1N4/k7/8/1P1r4/6p1/8/8/1K4n1 b - -,25,213,4894,44352,1127021,10826146 -1r1b4/1k6/1p3R2/1P3p2/B1n5/3Np1K1/P7/3R4 b - -,17,512,9137,273676,5464772,161545226 -8/5kP1/n7/r6n/1p1p1p1p/1P5P/4b3/2K5 w - -,8,198,1669,43281,444872,11947747 -8/2p5/1p6/1p3p2/5P1p/1nk1N3/6K1/r7 b - -,28,308,7047,74771,1740511,16532141 -b6b/1n6/P3kP2/2p5/1BP3P1/p1N3p1/4K3/1N1R4 b - -,11,340,5252,153285,2719670,77144799 -1n1qk3/R4N2/2rP4/3K1P1p/1PR2P2/3p4/4B3/2q5 b - -,38,1128,39745,1095850,38910383,1018993899 -r1q2b2/1b1npk1r/p2p4/2p4p/P2P1N2/4P1P1/K2Q1PP1/R2N1B1R b - -,32,1241,41181,1605409,55053049,2156245240 -r1b1k3/1p1qbppr/n1p1p2n/3p3N/Pp5P/3P1P2/2P1P3/RNBQKB1R w KQ -,31,910,27511,850320,26347156,853400521 -8/k6N/5b2/1P3R2/2K3nP/8/8/8 b - -,20,392,6798,133365,2196898,44226521 -2k4r/p2n1p2/1pp1p2b/8/1P4K1/1Bn5/P4r2/2R3NR w - -,28,1316,33187,1470651,37790214,1612460756 -1r1r1bk1/np2p3/1P3ppn/1Pp4p/R4PPP/3P3b/1R1KB3/5q2 b - -,40,896,36305,800863,32598813,730867935 -2bkrb2/3r4/p1n2ppp/2PppP1P/Q1p1P2B/N2R1N2/P2P4/3R1K2 w - -,40,1165,47752,1315395,54692164,1479111477 -3Nk3/pr6/b2p3p/5P1P/Pb1p4/6pR/QrPRB1P1/4K3 w - -,32,772,21856,557635,15941873,414687932 -8/8/8/5kN1/8/1P1K1P1p/7P/r7 w - -,14,258,3227,52527,634891,10175375 -2bkrb2/r6p/p1n2pp1/2PppP1P/Q1p1P2B/N2R4/P2P4/3R1KN1 b - -,34,1354,40566,1646818,47953842,1966127847 -5b2/8/rp2bqN1/p1k2p1r/PpPpP3/1Q5P/3P1PB1/RN2K2R w KQ -,36,1169,40063,1365571,45338825,1586993472 -6b1/1r1Bk3/1p2P2N/P4P1K/6P1/7b/2n5/4B1R1 b - -,22,479,9494,227321,4840050,123149209 -8/7Q/4pb2/2Bp3P/k1BP4/8/2R5/K7 w - -,42,417,16000,150843,6017905,57851283 -5b2/3K4/k7/8/7P/8/b7/5R2 w - -,20,341,6023,107880,1825885,33504996 -4n2k/7r/5RBp/ppbp2pP/3P2p1/8/R1P2KQ1/7N b - -,24,854,18718,686519,14817395,553657877 -5N1k/5n2/1N1p2Q1/1r6/P1pP3p/1P3P2/7P/2K2B1R w - -,45,703,29401,442757,17568802,267806956 -1r6/p1p2kp1/n3b2p/Pr2PN2/2P1P1P1/1P1KbP2/1R2N2q/8 w - -,26,1266,27946,1312957,28720751,1307899410 -n5n1/r4k2/2B2pr1/1P1Pp3/3B1P1P/2pP4/6q1/1NR1KQ1R b K -,44,1230,48824,1453359,55283849,1738897955 -6k1/5bbr/np1p2Bp/Pp3RpP/3P2p1/1R2K3/2P3QN/8 w - -,47,967,41254,834091,34313688,718787921 -6nr/3k1p1p/N1r1p1pb/7P/b1p1PqP1/B4P2/PQ1P1K1R/R7 b - -,38,1469,52988,2038434,74722661,2869188828 -1r5k/5b2/1p3R1P/1Pnp2B1/6p1/3p2K1/8/1b3B2 w - -,26,650,16381,397279,10092214,245503541 -2r3k1/2q5/1pn1p3/pp1NBp2/P4Pp1/3Q3b/5K2/6N1 w - -,42,1276,47763,1465541,51241802,1602634571 -3k1b2/p3r3/1P1n4/P1p1p1pP/2P3B1/R4R2/6N1/4K3 b - -,22,796,15796,558481,11229188,387831024 -8/k7/5n2/5b2/1K6/8/4R2P/2b5 b - -,31,602,15821,287822,7243596,127061047 -8/7k/8/6n1/7p/1P5p/2K5/3R4 b - -,10,207,2435,45050,540038,9809538 -5Bbr/3n3k/1p3pRP/1P1p4/8/1p1pN3/6BK/8 w - -,29,308,8940,116615,3318770,51797663 -k4b2/8/8/2pb2NP/3p1K2/P1P1Q1P1/1rN2P1R/8 b - -,32,1068,30180,1003136,27024460,899064161 -r4bn1/2q1k1pr/B4n2/1p3p1P/p1ppPPb1/P1P2Q2/1P2N2P/RNB1K2R w KQ -,33,1417,46496,1937881,63036784,2594427655 -5B1r/2k1n2p/1r2p1pb/p3pBP1/1P3P1P/P2p2K1/N7/R1B3R1 b - -,31,895,26286,800306,23028896,726579947 -1rb2kn1/Np5r/p2p1q2/2N5/PBP2p1p/3PPP1Q/1P4PP/3RKB1R b - -,40,1373,48190,1682078,57994902,2052406817 -4n3/2b5/bpk2n1p/3p1P2/P1B1p3/1Pp1K2P/8/R5NR w - -,22,549,11628,296410,6519338,168481245 -rn1qkb1r/3bp1pp/1ppp3n/p4pN1/P2P3P/1P2P3/2PN1PP1/R1BQKB1R b KQkq -,18,683,14009,532969,12152680,464400159 -r7/k5N1/8/1P6/6p1/3r4/2K5/6n1 b - -,28,245,6241,60472,1612682,16203952 -rn2kb1r/1b1pp1pp/p1p4n/6B1/2P5/5Q1B/PP1KPP1q/RN4NR b kq -,25,1055,26172,1046634,27721725,1085015460 -r1bk1b1r/1p2qp2/1n1pp1pp/pPp5/3P1nP1/B1N1Q2P/P1PNP3/1R2KB1R w - -,36,1253,43592,1492559,53997344,1839435123 -rn4r1/p2kp1bp/B1p4n/4BpN1/3P4/8/PP2KPPP/R1r4R b - -,28,1060,29354,1104057,31347985,1160018790 -3kN3/1B4Bb/3R4/1p2p1P1/1P4R1/p7/8/6K1 b - -,2,84,858,33564,382495,14360838 -2b1q3/p1r3p1/P1pp4/1PPn1P1k/1B1P3p/4R2P/R3K3/1N1Q4 b - -,34,1290,37282,1373233,40621023,1491287916 -k7/8/5b1N/6PP/2pNbK2/PrP1p3/5PR1/8 b - -,32,742,22353,511507,14865434,339075726 -r2k2nr/p1p2p1p/b3p1pb/1p1p4/2B1PqPP/N4P2/P1QPK3/R1BR4 w - -,28,996,25861,922972,25691235,917678287 -8/R7/6R1/2p3K1/2P5/5N2/8/3kq3 b - -,20,494,9429,252989,4987795,133406402 -rn1k1bb1/N2q2r1/1pQ1P3/6pp/3PPP2/P4N1P/1Pp1K3/1RBB1R2 b - -,41,1757,63303,2573261,93333024,3679279682 -1n2rk2/r2b4/1p5p/p2R4/P1P1pp1p/6N1/4P1B1/b4KnR b - -,40,1099,42408,1116063,42840366,1120402617 -1k6/6b1/4R2N/2b5/8/1K3N2/8/8 b - -,25,730,15174,426220,8377653,229021412 -3qbb2/7r/Bpk2Np1/2ppQ3/3p3P/P1P5/2NK1PP1/1Rr3R1 w - -,61,1858,95101,2817390,135245456,4046449515 -8/8/6b1/3k1B2/1p1p4/8/8/7K w - -,13,170,1925,25908,307807,4302673 -2q2bnr/p2k2p1/nrppb3/P6p/1p2P1QP/1P1P1PP1/R1P5/1N2KBNR w K -,32,890,29301,866320,29081582,897232471 -4n3/2b5/bpN2n1p/2kp1P2/P1B1pp2/1Pp1B2P/5K2/R5NR b - -,4,109,2448,75099,1725594,52722042 -2k2B1r/4n2p/1r2p2P/p3pBp1/1P3P1P/P2p2K1/N7/R1B3R1 w - -,32,848,25730,676096,21527913,564974667 -8/R1K1B3/6b1/5q2/P7/8/6k1/8 b - -,35,583,20163,334545,11340006,201412636 -rnbqkbnr/1p1pp1p1/p6p/2p2p2/7P/2P4N/PP1PPPP1/RNBQKB1R b Qkq -,20,458,10414,264849,6615556,182563435 -8/2k3P1/P4p2/2p5/PNP4K/7r/8/R7 w - -,2,30,656,9571,217819,3252712 -3knb2/p5r1/PP2B3/2p2RpP/1NP1p3/1R6/8/4K3 b - -,18,673,12133,445667,8319715,297602740 -Q1bq1b2/6pr/1p1pkp2/2p4p/3p3P/NpP3N1/P1n2PP1/1RB1KBR1 w - -,4,112,4344,118677,4599531,129605371 -1n4k1/BP6/b7/4pP2/2pP3P/5pr1/3n1K2/4R3 b - -,23,426,10051,185803,4470292,84965389 -1n6/2k5/1p6/6N1/2p2P2/1p6/3K4/8 w - -,13,145,1737,20833,245332,3121255 -1k6/4b2r/p2p3Q/Ppp2pP1/3R4/R2K3b/1P5r/2B5 w - -,32,847,24376,684652,19965076,575639390 -1b1k4/1B6/8/2P5/4p3/4N3/3K4/8 b - -,11,222,2552,48238,595884,11156196 -1k6/3r4/Pp4P1/3R4/2P1B3/6p1/8/3K2N1 b - -,16,408,5829,164130,2270408,64432996 -1k3B2/2N5/2b5/8/8/6r1/5K2/b7 w - -,17,556,8863,269265,4294486,127273595 -b1k5/b7/5r1p/2P4P/P3p1N1/2K5/8/8 w - -,15,358,4867,112905,1443737,33634974 -r1bn1r2/2Nk2pp/6P1/pP3p2/3QP2P/1P1PBR1q/2P1N1p1/4K3 b - -,2,95,2475,101758,2829591,113984424 -6n1/4br2/1r2kp1p/pp5P/P5P1/N1pP1P2/6BK/2B4R w - -,23,486,11620,272425,6779311,168934332 -b5r1/8/R7/p4B1k/q1P2P1p/8/1K6/8 b - -,33,629,19244,368122,11340920,219458585 -2r5/3n1k2/p2p4/P1pbp3/R3PP1p/6QN/B2K2P1/3N3R w - -,44,1008,41960,965759,38982826,901953543 -8/3kb2r/5pRp/Bn5P/P4N2/3P4/4K3/8 w - -,29,576,15701,314946,8609085,178643470 -8/2r1k2b/1pB1P2N/P4P1K/6P1/n7/6b1/4B2R w - -,29,682,18589,461486,12697898,323610449 -8/2Pk4/5bp1/1R4rp/3pQ2P/2R3B1/3n4/3K4 w - -,61,1089,56822,1093864,51541676,1023700117 -rnbqkbnr/p1pppppp/1p6/8/8/4P3/PPPPBPPP/RNBQK1NR b KQkq -,21,587,13353,383626,9478984,280327824 -3n4/4Bk2/PPp2b2/6pN/2r5/N7/5K2/8 w - -,24,635,13737,351284,7605590,192320297 -k1nB4/8/7p/3p4/8/3p4/2N4n/3b2K1 b - -,19,291,5576,86948,1700531,26598130 -8/8/np4k1/8/8/5p2/8/K5n1 b - -,16,47,774,4378,75110,386312 -1r6/4kN2/1p2B1R1/1P5K/P7/8/1b6/4b3 b - -,26,699,18142,490834,12219958,325421646 -rn6/p3k2p/2pb1B2/1r3p2/6PP/8/1P3P1R/2K3R1 b - -,6,160,4866,123492,3618744,93256723 -2n5/3r4/3b1pRp/3k3P/P7/3P3N/3B4/5K2 b - -,28,800,20415,549219,13599890,357336646 -4k3/8/8/3r1P2/8/2N5/5K2/4B2r b - -,27,365,9847,142079,3771057,59231312 -r1b1kbnr/p3p1pp/np1q4/2P2P2/N1Pp1P2/P2P3P/4P2R/R1BQKBN1 w kq -,25,869,23999,808429,23713073,805999165 -8/2p5/1p6/1p3p2/5P1p/r1k5/3n2K1/5N2 w - -,9,216,1809,42095,357935,8204087 -1k6/2b4r/p3Q3/Ppp2pP1/3R1B2/3K3b/RP5r/8 b - -,27,1081,27461,984986,26190884,907367945 -3rnb2/4p2p/3k4/p4n2/2p2r1P/2ppp2K/PB1NB3/RN4Q1 b - -,38,1284,44196,1409832,48066950,1528579501 -8/4k3/3p1N1n/1B4n1/4p3/8/1q6/3K4 w - -,18,579,7726,249063,3331810,104408670 -1r3kr1/1bp1p1bp/1p1qB1p1/p3P3/P1P1NB2/1PK2P2/2n3PP/RN1Q3R b - -,41,1648,63682,2506103,93151491,3624453968 -8/6b1/1kB1P3/8/8/QK3p2/6P1/8 b - -,13,407,4987,152651,1906462,58102356 -2r1kb1r/p3p1pp/n4p1n/1pp5/1QN1p1PP/2PP4/PB6/RN2KBR1 b Qk -,25,809,19480,635042,15605744,517586062 -6k1/5b2/8/2b5/3B1K2/6p1/6P1/3n4 b - -,22,367,8755,117707,2826622,35714349 -3K1kn1/8/8/5P2/1P4p1/pNr5/8/5N2 b - -,20,243,4686,58300,1119319,14869829 -8/7k/8/7p/4P2p/5n2/2R3K1/1B6 w - -,19,225,4061,43101,821569,8509510 -4N3/8/1b5N/p4p2/P4P2/5k2/4r3/K7 b - -,28,239,6057,64447,1519169,17351912 -2B3nr/q2bp3/1r5k/2p1P3/6pP/3B2P1/3b1P1K/5RNR b - -,44,1138,48127,1263011,52656097,1411190390 -6k1/3BR3/5K1P/8/3n4/8/8/8 b - -,10,229,1771,43044,307923,7352003 -Q6R/6P1/1P6/3b4/3p1k2/1r1P3K/8/3N4 b - -,23,743,14615,467335,8874555,290160805 -3R4/1k5b/5P1N/5N1P/2p4K/2P5/1r6/2r5 w - -,28,765,19091,531682,12871844,363928546 -8/8/6k1/1n1P3p/4K3/1P5p/1R6/8 b - -,14,197,2621,42159,551409,9286486 -b3k1r1/8/1N6/5np1/pBp2P2/4p1P1/K5B1/b5R1 b - -,31,1084,32583,1084673,32643022,1051915149 -r3kbnr/p3p1pp/np1P4/5b2/2Pp1P2/P2P3P/1N2P2R/R1BQKBN1 b kq -,29,679,18504,483893,13448428,380414864 -5n2/8/P2R4/k7/1p6/5N1P/2B3K1/5n1R b - -,10,356,4006,140384,1720449,59528612 -5k2/p7/nR1K4/8/3p4/5p2/3b4/6n1 b - -,22,278,5608,85064,1722859,26334618 -rnbqkb1r/1pp1pppp/5n2/p2p4/1P4P1/3P3P/P1P1PP1R/RNBQKBN1 b Qkq -,31,894,28300,803592,26228357,755323044 -3k2b1/2p1r3/5b2/pN3pPr/p1Pp2R1/P2P1P2/2K5/B3qBN1 b - -,50,1018,45703,961461,41057144,890092047 -1nb3nr/2p1p3/P4rk1/bpP2pq1/3pP1Q1/N2B1KPP/P4P1R/1RB3N1 w - -,33,1088,35253,1159999,38919041,1294765096 -1r3bn1/pb1kp2r/np6/2pP1ppQ/P2PB2P/BP3N2/5PP1/R1N2K1R b - -,32,1214,35935,1415359,42098702,1698078596 -4k3/5R1p/2b4P/3pr3/p1p5/1Bb3p1/4K3/8 w - -,3,81,1409,36425,603106,15855197 -Nb4nr/1pq5/7k/5Ppp/ppP2BPN/3B3P/P7/R2K1R2 w - -,34,865,29022,808322,26568725,783781252 -2r1k3/5b2/p2p1n2/P1p1p3/R3PP1p/2K2Q1N/B5P1/3N3R b - -,27,899,22966,810603,20307114,743252379 -Bnbqk3/3ppp1r/p4Qp1/1pp1b2p/PP6/B3P1PP/3PKP2/RN4NR b - -,28,1164,31138,1228771,34022357,1307417861 -r1bqkb1r/p2p1pp1/np2pn2/2p4p/P4P2/8/RPPPP1PP/1NBQKBNR w Kkq -,21,549,12762,362769,9158647,276044908 -1k6/8/r2P1pP1/p1p5/P1P2B2/1Pq2p2/N7/1R3KR1 b - -,24,508,11916,256880,6187366,139703162 -8/7k/1p6/1n6/K7/8/8/5bn1 b - -,19,45,930,4086,87948,401547 -7R/8/6k1/2PP4/K3p3/5rp1/8/6q1 w - -,19,571,8706,251525,3735223,108672474 -4nbk1/5R1r/1p4Bp/Pp1p2pP/3P2p1/4K1N1/R1P3Q1/8 b - -,16,706,11343,461831,7818830,308038950 -6k1/3Pb3/4r1pr/p3p2p/5P1P/P1pQP3/3B3R/2RNKBN1 b - -,27,1054,25847,1046369,25147662,1050919566 -6R1/5k2/8/3r1P2/8/7p/N7/4BK2 b - -,16,392,6148,145038,2313682,54314448 -4r1k1/p5B1/PRP5/2P4r/2N5/5Kb1/1P5P/2qB4 w - -,31,1440,38446,1671742,43639275,1823785173 -1n3bkr/2B4p/7Q/pppn3b/P2pP3/3P4/2P2K2/RN6 w - -,40,898,33523,759718,27090817,626870788 -b3n1r1/1k1B4/8/3p2pp/P2P4/K7/7Q/4n3 b - -,17,487,8708,239912,4737990,128535406 -rn1q3r/ppp2k2/1B3n2/3pp1pp/PbP2p2/1P1P3b/R2QPPP1/1N2KBNR b K -,54,1565,78731,2361793,112535344,3508229269 -4Nk2/8/B7/1P4P1/7B/p7/6K1/3b2R1 w - -,21,231,5327,62751,1576124,19501292 -R2q4/p7/1kB1PQ2/8/1P4p1/3R4/2K3Pb/8 b - -,28,1466,36171,1710905,40509680,1800233127 -3r4/1p2pk1p/7n/3p1Pp1/2P1R1b1/2B3P1/5N1P/2K2B1R b - -,27,1015,26706,955798,25011147,872130046 -2k5/1p3pnp/r2pp2b/4Q2P/P1pP3B/R4B2/2K1P3/6R1 b - -,24,1320,30518,1545207,35921264,1717806436 -rnb2r2/1pppqk2/1b2p3/pP3pp1/P2PP1np/5P1K/1BPNQ1PP/R4BNR w - -,26,927,24504,878056,24452479,878851517 -8/p2pkNr1/b6p/1n1p1P1P/1b4p1/P5R1/QrP1B1P1/3RK1N1 w - -,6,166,6135,172559,6254109,180383520 -rn6/p4k1p/2p2B2/1r3p2/1P3bPP/8/5P1R/2K3R1 w - -,4,124,3459,103918,2885124,85692245 -8/8/PP1kN1P1/8/3p1p1R/3P4/5N2/r2b2K1 b - -,21,418,8353,187264,3683651,87323387 -1n1qBbr1/Nb2p1pp/3Nk3/2ppP3/P2P1pn1/1r4P1/1BP2P2/2RQK1R1 w - -,39,1415,52780,1849913,69490484,2375280195 -3qk1nr/p2b3p/n2p1P1b/p1pPp3/P5p1/RrP5/1P2PP1P/1NB1KBNR b Kk -,38,829,30003,690708,25079107,600014344 -1k2N3/8/2b5/7r/8/B7/5K2/b7 w - -,17,569,9037,286191,4541731,140006780 -7k/rp6/1P2p1p1/2Rn1p1p/5b1P/2r5/6b1/4K3 w - -,12,484,5919,232781,2956875,113343168 -1B3k2/6r1/8/1p1ppK1r/4N3/6P1/Rp4N1/6b1 w - -,3,109,2464,83244,2042045,67510217 -1r1rk3/p4RB1/P1P5/2PPb1q1/B7/2n3P1/1P5P/1N2K3 w - -,34,1270,36245,1371846,38056382,1435445809 -8/N7/3p1N2/8/2b2k2/4R3/8/2Kn4 b - -,19,505,8063,196105,3233898,76567266 -rnbqkbnr/pp1ppp2/2p5/6p1/8/1P1P4/P1PNPPPP/R1Q1KBNR b KQkq -,26,668,19090,508223,15471034,428553879 -rnbqkbnr/pp1ppppp/8/2p5/2P5/7P/PP1PPPP1/RNBQKBNR b KQkq -,21,420,9998,229003,5989877,151861033 -3Qk1B1/r7/2p1p1p1/ppP1P1Bp/PP6/3RKP1P/6P1/1N4R1 b - -,0,0,0,0,0,0 -b4k2/6R1/1P2B3/p5P1/P2bP3/5p2/3K4/8 b - -,18,441,7035,157818,2604502,56088894 -1R1r4/p4k2/PN1n4/8/3p2K1/B4p2/8/4b1n1 w - -,18,552,11212,314788,6650080,180453913 -7k/8/3r2p1/p3p1bp/PR2PP1P/8/3QK1R1/3N2N1 b - -,22,836,16784,653017,12807786,501842305 -1n1qnbr1/1b2pBp1/2k5/2BpP2p/P2P4/2r2Pp1/2R5/3QK1R1 b - -,30,1060,30226,1061272,30870529,1089539921 -2b1r3/2Np3k/8/p1P2p2/Pr3PPp/1P1n3P/2QK4/1RN3n1 b - -,41,927,34183,832680,28560792,741162437 -8/1k6/3bPQ2/8/8/3K4/6P1/5B2 w - -,31,497,15116,192073,5772398,66448989 -r1bq1b1r/2p3p1/np1pkp1n/1N2p2p/3P3P/1pP1PQ2/P3NPP1/1RB1KB1R w - -,39,967,37011,992244,37539671,1071175430 -7k/5R2/3N4/1p1pP1BP/P7/3pn3/3K1PP1/3b4 w - -,40,621,20244,292574,8942192,125413036 -2b3n1/r4k2/1n1P4/NP3Pp1/p7/P3K3/2r2N2/2R1b3 b - -,40,750,28863,568056,21016105,430680874 -3R4/1B1nk3/5r2/2p3bn/P2p3r/2p5/8/1b1K4 b - -,46,828,33784,598033,24251068,436566564 -rn1kq2r/1bQ4p/2p5/p1Pp4/P5n1/2Np4/1R1P3R/2B3nK b - -,1,25,811,18254,609359,13551896 -rnbk3r/pp1pb2p/2p1p3/q6n/P7/NPPp3n/Q2PN1KR/R1B5 w - -,21,886,18555,756915,17156626,685188357 -3krb2/2p1p3/4b1r1/pNq2pp1/p1Pp1P2/3P1P1P/PB3RB1/2K3NR b - -,28,656,19516,461581,14250623,344960844 -1r1r1bk1/1p2p3/1Pn2ppn/1Pp4p/R2P1P1P/5b2/R2K4/5q2 b - -,48,694,33170,543036,25740566,446147572 -r1b3r1/p1p1k1pp/n2p1b2/1N2P3/P3P3/2P3PQ/1P3P2/2R2KNq w - -,34,1069,32070,1076320,32085484,1118271017 -8/R7/6R1/2p3K1/q1P5/8/3N4/2k5 b - -,19,607,11252,325554,6366538,175334515 -8/k3Nr2/2rR4/1P1n4/6p1/1K6/8/6n1 w - -,20,576,11472,334167,6738685,196416999 -rnbqkb1r/pp1ppp1p/3P1n2/2p2Pp1/8/8/PPP1P1PP/RNBQKBNR b KQkq -,24,651,16373,484097,12638427,398568794 -rn3k2/p6p/2p2B2/1r3p2/1P3bPP/8/1K3PRR/8 b - -,28,606,15863,365445,9739870,236812405 -n4kn1/1r1B4/5pr1/1P1Pp3/3B1P1P/2pP4/2Q2K2/1NR3qR w - -,4,120,4247,127680,4640585,140986497 -k7/1b6/4N3/8/8/r1B5/3Kpb2/8 b - -,31,550,17087,283639,9059362,147248347 -6b1/2k3P1/8/1P6/4B3/p7/4KB2/6R1 w - -,41,496,18254,232796,8291048,107309729 -5q2/3Bk3/3p3n/3PNPb1/4pr1R/8/7p/2n1K3 w - -,22,661,13215,419254,8402399,277376412 -5r2/6k1/3rB3/1p6/3N3Q/Pp6/1b4K1/8 w - -,40,987,36849,953873,33892842,911858331 -8/5Pr1/3b3k/2P5/1p4P1/8/2RKq3/1B6 w - -,2,58,927,23945,477154,12713350 -6br/8/2B2k1p/r1Pp4/6K1/1P2p3/4R3/4B1nR b - -,24,703,16110,470795,11403371,333269385 -N1b3r1/1r1p1p2/6k1/p7/PnP2PPp/1P1P3P/1R1K4/Q1N1B1n1 b - -,27,536,14468,331191,9173502,228588165 -8/P1n1kB2/8/7R/8/1p2KN1P/8/2R2n2 w - -,7,115,5025,74174,3096221,45007518 -r2qkbnr/2ppp2p/bpn3p1/p4p2/P1PP4/3BP3/1P1B1PPP/RN1QK1NR b KQkq -,28,1012,29612,1063746,32482656,1171831730 -8/2n4k/1p6/8/8/K7/8/5bn1 b - -,22,104,2294,11810,265778,1325810 -6r1/6kb/n7/6K1/8/5B2/3p4/R2r4 w - -,23,609,12067,377649,7689801,257212678 -k5r1/5K2/8/8/3P4/P6R/4N3/8 w - -,24,358,7557,111974,2413980,36354752 -8/3N1B2/P5P1/2b4k/3p3P/8/1KR3N1/4r3 b - -,24,633,12059,333945,6379014,182796289 -r5n1/p2bk3/q2pn2P/2p1pp2/pPP2pPp/QN1P3R/2K1PP2/R4B2 b - -,35,1169,41663,1400040,50483823,1708393606 -3k1bnr/p2B1r2/nqp3pQ/P2p3p/1pP1P2P/1P1P1PP1/8/RN3KNR w - -,39,1439,51152,1818075,64502449,2239986265 -2k2r2/n7/p7/PP1B3r/3B3P/1P6/7K/2N5 b - -,26,824,20864,599758,15575100,419981700 -rnb3nr/2p1p3/p3k1q1/1pPp1p2/4PQ2/N1b4P/PP1P1PP1/R1B1KBNR b KQ -,40,1465,49680,1790569,60208933,2150067704 -rnbq2r1/p2p3k/1p3p2/1P1pp2p/3P1NP1/b1P2K2/4B3/2R1B2R w - -,33,1029,32522,1011499,31880559,997578719 -r4B1r/2k1p2p/1n4pb/pP2p1P1/1P1q1PBP/P2p2R1/6N1/RNB1K3 b - -,42,1146,46069,1298309,50413572,1460096097 -3Bk3/5b2/7P/P3P3/6P1/8/2K5/8 w - -,17,178,2659,31353,482901,5640124 -r1b1k3/p2p1Nr1/3b3p/1n1pp1pP/2BB1P2/P6R/Q1P3P1/R3K1N1 w Qq -,50,1407,65365,1837308,82946572,2340651116 -8/1P6/2nk4/2p5/2PpPKnb/3P4/1p6/8 w - -,8,148,1393,29835,329324,7341872 -rnbq1knr/pp1p2bp/5pp1/2pNp3/6P1/4PP1P/PPPP4/R1BQKBNR w KQ -,31,724,22093,542753,16533109,429123454 -6n1/1k2b3/3pb3/2PPbPp1/3R2Pp/p1N1KN1P/8/1B4R1 b - -,25,938,22393,801728,19301945,668190713 -4r3/8/8/1k6/3K2p1/8/8/1r6 w - -,3,93,355,11349,48362,1517631 -5k2/8/4p1b1/4PB1p/1p2P2P/8/4N3/3K4 w - -,14,147,2162,21909,326936,3398007 -2R1r3/1k2bR2/1p6/1P2pp2/p7/6K1/PN6/1n1B4 b - -,13,351,5541,148510,2749113,74681240 -Rr6/2k1b3/5r2/p4p2/4p2p/R1P4B/5P1P/2N1K3 w - -,24,879,23281,742352,20644948,623376446 -8/3P3k/p7/P2Q4/N7/2p4B/2R1p3/4K3 w - -,45,187,7615,36793,1446289,8255900 -8/2k5/1b2P3/8/6B1/7Q/6P1/3K4 b - -,13,316,4064,110424,1308305,37294309 -rnbqkbnr/p1pppp2/6pp/1p6/2P5/N7/PPQPPPPP/R1B1KBNR w KQkq -,29,601,18344,419743,13267029,331139265 -6bB/2n2k2/7p/8/6K1/1Prp1B1R/4p3/R7 w - -,39,894,31680,789802,27467431,727062945 -4B3/k7/8/pn2p1r1/3r2p1/8/1b2K2B/3N4 b - -,33,551,17684,317618,10147846,190633205 -3k4/8/7B/3BP1P1/pp1K1R2/P6p/1P6/8 w - -,34,256,8350,59322,1893625,14730774 -r1bk1b1r/1p1ppP1p/p5p1/q2p2P1/n4Pn1/P1PK3B/1PNQ3P/RNB3R1 b - -,30,704,21736,574965,18110356,526425418 -rnbqkb1r/2pppp1p/1P4pn/p7/6P1/5N2/PP1PPP1P/RNBQKB1R b KQkq -,22,567,13851,398168,10614775,330150524 -2b5/r5k1/1n1P4/NP1n1Pp1/p3K1N1/P7/2r5/2R1b3 b - -,48,973,41312,879086,35338849,772478838 -K6k/8/8/1PnN4/8/8/8/8 b - -,11,128,1248,13198,135708,1479855 -2R5/8/4k3/5b2/8/8/5r2/4n2K b - -,29,392,10475,137131,3658019,48054593 -rnbqkb1r/pp1ppp1p/5n2/2p3p1/P3P3/6P1/RPPP1P1P/1NBQKBNR b Kkq -,25,789,21212,664019,18975771,602004821 -rn2qb1r/N1pkp1pp/Qp2b3/5P2/2pP1Pn1/4P2P/PP1N4/R1B1KBR1 b Q -,29,1084,29347,1119593,31400393,1209855634 -8/8/8/1pkn2r1/6p1/1K6/8/4R1r1 b - -,25,392,10330,155583,4313376,61791963 -5k2/8/1P2B3/p5P1/7r/1R6/1K6/8 w - -,27,470,11868,189295,4696841,73701411 -8/8/1kB1P3/8/Q7/1K3p2/6P1/b7 w - -,32,310,9931,117560,3757629,47422309 -8/P3k3/n7/7R/3NK3/1p5P/8/5R2 w - -,45,404,15690,147146,5624702,55252700 -Q7/2N5/6rk/8/1p5K/3B3p/8/8 b - -,17,608,8479,280729,4022357,128988129 -1B6/5n2/5k2/5P1n/2K5/5p2/1r6/6B1 b - -,28,471,11692,201461,4884744,85289915 -6k1/8/1p6/3n4/4b3/8/7n/3K4 b - -,25,97,2470,9975,250467,1144794 -1k4r1/3q1n2/3N4/Q1PPp3/1KP2R2/5Ppp/8/6R1 b - -,32,1117,28978,1038527,26646996,965037952 -q7/1r6/5Pk1/4b3/1pP2RP1/3Kn3/B7/8 w - -,15,677,10431,445085,7367034,301127327 -8/b1k5/7p/P4prP/2nB4/3P4/4N3/4KR2 w - -,28,745,18441,481845,11393547,294638699 -r3q2r/pkpn1pp1/1p3N2/2bPpP1p/P3P2P/6P1/1P1PK1B1/RNBQ1R2 w - -,32,1142,37939,1308456,44704167,1505196286 -1rk5/8/1p3R2/1P3p2/P6K/4p3/1bBn4/R3N3 b - -,21,529,10772,285551,6179278,169500472 -r2k1bn1/pp5r/B4p1p/1Pp1p2Q/P1P4P/2Rq1b2/8/1NB1K1NR w - -,31,1303,37968,1512471,47842041,1822685549 -B7/2kN2B1/8/p5P1/1p1K1R2/P6p/1P2P3/8 b - -,8,318,2491,95673,790553,29286816 -6nr/1p3k1p/5p1b/pqp1p1p1/1PN3P1/B1P1pPQP/P2PK1BR/3R2N1 w - -,26,632,17801,439828,13227640,338926504 -3k1b2/1R6/2P1r2n/3p1P2/8/6n1/2KN4/8 b - -,30,829,22022,529034,13985069,310633944 -Nb4n1/4B1qr/1p5k/5Ppp/ppP3PN/3B3P/P7/R2K1R2 w - -,33,825,25883,703438,21822961,630384807 -1rb5/5k2/1NQ3p1/pP1p1p2/P4PnP/3pR2N/3BP3/2R1KB2 b - -,19,850,14424,630068,11471110,496449295 -1r6/k7/8/1P6/6p1/2K5/8/r5n1 b - -,27,210,5621,33228,893481,5188840 -8/8/2Np4/8/5k2/1b3N2/3K4/3R4 b - -,15,396,5451,141447,1851577,47970289 -8/8/2P5/1K6/5k2/8/7p/8 b - -,12,96,1327,9918,159691,1277129 -rn4k1/7q/1pp1p3/pR1p1pp1/P4P2/B2Q1P2/3K2b1/N5N1 b - -,32,1231,37353,1383526,41399299,1481420726 -k7/1r6/p1QB2r1/Pp6/1P1p4/3K3b/R7/8 b - -,19,665,12529,426489,9088751,300248326 -6nr/pk5r/n6Q/Pqbp3p/Rp1PP2P/1P3PP1/4N3/1N3K1R w - -,35,924,30560,886202,29178235,895231810 -1kb1nb2/8/3p3b/3P1Pp1/p1P3Pp/4K2P/3R1N2/4N1RB w - -,27,423,11278,192816,5135792,92716727 -8/1r6/2N1p1k1/p4p2/PN3Pp1/7b/8/4K3 b - -,22,344,6657,101975,2011260,29741842 -8/8/K3k3/4N3/3b3P/5p2/3r4/8 w - -,12,337,3825,101687,1113550,29097330 -2n3k1/1Q2p3/N7/p4P1P/3K4/1b5p/1R1r4/1r5n w - -,6,238,6988,236166,7102659,235089853 -rnbqkbnr/p1p1pppp/1p6/3p4/P1PP4/3BP3/1P3PPP/RNBQK1NR b KQkq -,29,1095,31813,1194035,35783821,1339971650 -8/2k4r/1N4n1/8/3p4/8/K2N4/8 w - -,17,372,5882,130145,1999112,43926871 -8/8/4b3/1k2p3/4B3/b1P3Np/2n5/1K6 w - -,19,481,8111,198356,3210337,77007113 -1n1q1br1/Nb2pkpp/8/2ppP3/B1NP1pn1/1r4P1/PBP2P2/2RQK1R1 w - -,38,1424,52420,1909764,70870344,2536372238 -rnbqkbnr/p1pp1pp1/1p5p/4p3/3P4/2N1B3/PPP1PPPP/R2QKBNR w KQkq -,31,954,29751,923031,29225863,922852194 -7k/8/1p6/3n4/8/8/2bK3n/8 b - -,23,101,2208,8793,187895,904631 -8/4B2Q/4p3/1k1p3P/2BP3b/8/2R5/K7 b - -,5,189,1898,75272,809026,32027472 -R2q4/p7/nkB1PQ2/8/1P4p1/2P5/2KR2Pb/8 w - -,47,1249,54198,1358764,58320406,1455263430 -rn3b1r/1bq1pk2/p2p4/2p2p1p/P2P4/1KN1P1P1/1p2NPP1/R3QB1R w - -,35,1423,43585,1748763,53788828,2148282020 -rnbqkb1r/p2ppppp/1pp2n2/8/3N4/4P3/PPPP1PPP/RNBQKB1R w KQkq -,34,746,25626,614446,21437555,552424694 -1k6/q4n2/3N4/1QPPp2r/1KP2R2/5Ppp/8/6R1 b - -,4,127,2617,77806,1667741,51157750 -1N6/8/2nk4/4R2K/4P3/5Q2/8/8 b - -,10,335,2422,79879,621717,20331176 -r5nr/1b1p1p2/2nqNk1b/pppP2p1/2P4P/P4P1B/3RPK1P/2Q3NR w - -,38,1359,49033,1724704,61455258,2144036518 -b1N3n1/8/4P3/P1k5/5RP1/7p/8/1K6 b - -,14,311,4542,101212,1570409,34873759 -1rbk3r/1p6/p1pb2Q1/1q2P2p/5pnP/1PP2P2/P2K4/RN4NR w - -,32,1065,30810,1027346,29276092,987404399 -rnb1kbnr/pppp1pp1/4pq1p/8/2P1P3/1P6/P2P1PPP/RNBQKBNR w KQkq -,28,1014,28303,1011835,29006315,1029823913 -8/2q2P2/2P5/8/6kp/pK6/8/8 b - -,25,241,6189,64315,1580579,19198285 -3r4/3n2kr/7p/1R1b4/pNp4p/4PB2/1R5b/5K2 w - -,34,1254,41584,1486060,49150966,1733374396 -1B6/8/5k2/2B1nP1P/5n2/5p2/2K5/1r6 b - -,34,632,17878,307914,8235576,143957133 -r3k3/n6Q/p2p4/P1pP4/8/P2K3N/3BB2R/b5q1 b - -,33,1045,26720,877799,22791955,765249407 -5k2/2R3p1/8/pp2Kp2/P3PP1p/1b3Nqn/7P/3R2q1 w - -,37,1369,41900,1564566,43960095,1642723990 -4kb2/5p1p/2Pr1nr1/p3p1R1/1P3N2/pRP4b/3B1P1P/3K1B2 w - -,35,1232,40348,1409755,46039018,1603174863 -r7/n3k1b1/p2p4/P1pP1Q2/8/P2KBB1N/6pR/R7 b - -,26,1245,27305,1296203,28971358,1349277052 -rn3bnr/p7/b2ppkpp/1p1p1p2/PPPPP3/R2B4/5PPP/1NBK2NR w - -,36,681,24292,499254,17674073,391295115 -8/8/4k2p/rp1r3P/6p1/n1R1K3/8/8 w - -,14,360,5236,134308,1913147,50015253 -rnbqkbnr/p1pppppp/1p6/8/3P4/4B3/PPP1PPPP/RN1QKBNR b KQkq -,21,567,13085,367754,9267735,270355369 -rn1qkbnr/ppp1pp1p/4b3/3p2p1/2P5/1Q6/PP1PPPPP/RNB1KBNR w KQkq -,33,906,29311,842072,27253917,810869744 -2k5/4B2p/3pp3/5QbP/2pPn3/8/8/KR5B w - -,43,768,31300,545708,21453280,361792945 -b4b1n/6R1/P1pBkP2/8/p1Pp1pP1/N5P1/3RB3/1N4K1 b - -,12,446,6042,210925,3130861,106997061 -1r3b1R/1Bn3k1/p1bp4/P1p2p2/3P1p2/PK4p1/3B3q/RQ4N1 w - -,36,1409,47375,1744519,60885810,2172690393 -2r5/6kp/p4n2/pNpP2P1/P1n5/r2B4/5N1P/2bK3R w - -,30,1185,32276,1248532,33267562,1263069945 -rnbq1bn1/p2ppkp1/1pp5/5p2/P1P5/1R6/RP1PPP2/1NBQKBN1 b - -,22,593,13954,388565,9683337,282271232 -rnbqkb1r/pppppppp/7n/8/2P2P2/8/PP1PP1PP/RNBQKBNR b KQkq -,20,439,9785,239086,5902683,156402823 -rn2kbnr/p3q1p1/2pp1p1p/Pp1bp3/4PB2/1P1P2PP/R1P2P2/1N1QKBNR w Kkq b6,36,878,30628,809788,28130696,786452515 -3K1k2/8/8/8/1P2n1p1/4Nr2/8/5N2 b - -,21,286,6223,86502,1907841,26766383 -1B6/2r1k3/1b6/1p1pp1N1/8/R3NKP1/1p6/7r b - -,42,1200,44895,1202493,43888003,1137469480 -8/8/2K2k2/5r2/7p/p7/8/3R2b1 b - -,27,449,10968,174616,4269726,67127092 -8/6k1/4P3/8/P3P3/5N1p/N7/5K2 b - -,8,144,854,13893,96005,1566059 -1N6/8/3p1P1k/p6P/2nK4/1r6/4R2p/3b3n w - -,21,637,11264,331718,5726109,166498546 -1n3b1r/5k1p/7Q/ppp4b/P2pP3/3Pn3/2P2K1B/RN6 b - -,27,839,19179,609077,14764327,472785325 -2bq2nr/rp2bk2/p1np3p/4pppP/P1N5/1P3N2/1BPPPPP1/1R1QKBR1 b - -,29,864,23209,685600,19400987,576083703 -7k/8/n5P1/r7/1p1p1p1p/1P4nP/8/2K2b2 w - -,6,148,700,16882,82100,2039595 -b1r5/p2k4/2q4n/2P1p3/p1PPNp1p/4RPp1/1K3PB1/3QR3 b - -,36,1191,41749,1399507,50230465,1702239670 -3N2b1/1n2r1k1/8/8/3K2p1/4B1P1/8/7R w - -,27,560,13183,296537,6947478,162230893 -1r4rk/1p6/n7/Bq1pp1p1/P1p1R1bN/6PK/2P3nP/RN4b1 w - -,3,134,3418,145880,3891950,165102035 -7k/4r2B/6K1/P5b1/1p6/R6p/4N3/8 w - -,21,473,9211,206799,4221683,92134171 -k7/5n1p/P1bq4/3p1N2/7B/3pn2K/8/8 b - -,40,559,21068,304764,11159060,165490444 -rnb1kbnr/pppp1pp1/4p2p/8/P1PPP2q/1P6/5PPP/RNBQKBNR b KQkq -,38,1219,44735,1468477,53005646,1772443749 -4k3/nb1n4/8/P1p3B1/2PpP1KN/1p1P4/8/6b1 w - -,20,413,7554,162298,2882534,64299971 -7k/8/2K2N2/1P6/8/5n2/8/8 b - -,9,125,925,12793,118420,1534735 -6R1/p6k/P1P5/2P3r1/5rBK/8/1P6/8 b - -,24,363,7542,133544,2816718,53669030 -5r2/1k1n1p2/1p5b/pPp1p3/B7/2R3RK/PN6/8 b - -,24,709,17240,505865,12209803,357980657 -r2k2n1/4b2q/B4np1/5p1r/pP2PP1P/2P1B3/R3R3/1N2K3 b - -,27,938,27397,923566,29717881,990013302 -b6b/1P6/5P2/4k1P1/2P5/NpNR2p1/4K3/8 w - -,37,291,10271,108370,3635558,47297550 -4n3/8/1p1kN3/8/5P2/8/2K5/8 w - -,16,147,2087,22063,287971,3155701 -r1bn3r/p1p2ppp/1N1k3n/1P4P1/1b1ppq1P/BP3P1R/Q1PPPK2/4RBN1 b - -,46,1114,46048,1185296,49263201,1328847092 -k4Nr1/8/2n5/6N1/3p4/6b1/7n/3K4 w - -,14,398,5497,156938,2225359,64449313 -N1b2knr/ppq3bp/5p2/2ppp1p1/6P1/2P1PP1P/PP1PK3/R1B1QBNR b - -,29,639,18610,439525,12976419,325092927 -1rb1qbn1/ppppp1p1/3r2k1/P7/P1P3Pp/B4P1P/3P3N/RN1Q1KR1 b - -,26,652,16804,451529,11890030,340003752 -3k3r/1R6/2P4n/3p1PN1/8/5NP1/4n3/3Kb3 w - -,32,625,17712,372298,10063297,224066934 -rnbqkbnr/pp1ppppp/8/2p5/P7/R7/1PPPPPPP/1NBQKBNR b Kkq -,22,590,14523,382134,10296014,279660335 -rn5k/3p4/1pp1p3/pR3pp1/P4P2/3Q1N2/2NK1Pb1/q1B5 b - -,28,1071,29035,1041797,28700770,991502136 -r2qkbnr/1pn2p1p/3pp3/5Pp1/P1p3B1/1P1P4/1B2P2P/RN1QK1NR b Kkq -,33,1131,37055,1282740,42093683,1489148795 -rnb2q1r/pp1Pbk1p/4p1pn/2p2p2/8/1P2PP2/PR1PQ1PP/2B1KBNR w K -,30,791,24008,675596,21717632,639131856 -8/5k2/8/1K2P3/1N5P/2p2p2/4Rr2/8 w - -,23,300,6528,92121,1933131,29935974 -6k1/5b2/1P4B1/p5P1/P3Pp2/6R1/7n/2b1K3 w - -,19,323,5711,104542,1910702,36388719 -4k2r/6pp/2p1pp2/p2BPP1n/1bPp4/2N4N/1rR2K1P/6R1 b - -,30,1112,33204,1144379,34521839,1156805166 -4Nkb1/8/B3R3/6P1/1P6/p5B1/6K1/7R w - -,54,312,14811,136516,5875514,66482849 -1n6/rb2B1b1/1P4k1/pP2pr2/2P1P1p1/1N2K1P1/1R4BP/7R w - -,39,1116,40499,1175188,42415422,1242564178 -2b1kb1r/r4ppp/p1n5/1pPppP1P/Q1P1P2R/N4K2/P2P4/R1B2nN1 b k -,37,1008,35069,999247,33769865,1008932818 -br4r1/1B4B1/p6p/1Np4k/1P2P3/3p4/P7/2RK2b1 b - -,25,772,20894,609009,17623759,497427440 -b7/b3rN2/1k6/7P/P3p3/8/2K5/8 b - -,18,250,5074,64680,1438413,17468913 -4k3/8/8/2n3QP/3P4/N3K3/8/8 w - -,29,264,7991,65940,1957673,16598011 -3b3R/1N2k3/3r4/B2b4/p1Pp1p2/P2P1N2/4K3/6r1 w - -,33,1096,30754,962307,26127958,792804880 -8/1k6/8/3q1PP1/r6p/7K/8/R3B3 w - -,16,636,11101,395887,7421415,248909791 -8/7n/P5n1/1k3P2/1p6/1B3R1P/3R4/1K4N1 b - -,14,551,7299,270265,3725747,133556796 -8/n6B/r4b2/P1k1p1pp/1R4bP/2PPP3/8/B3KN2 w - -,27,596,15759,362146,9601859,226462631 -1n3R2/8/3r3b/2ppk1pn/P1p4r/2K2P1P/6B1/1b6 w - -,16,442,6852,202243,3195854,97017941 -4k1n1/8/2N5/1K3P2/1P4p1/p7/1r6/5N2 w - -,18,329,5472,103664,1693159,32862274 -7k/5b2/1P4B1/p5P1/P3Pp2/5R1r/3nK3/2b5 w - -,20,528,9190,245831,4390284,118092298 -r5r1/p1p2kpp/n3b3/P3PNb1/4P3/R1P2PP1/1P5q/4K1N1 b - -,51,913,40756,731549,32350563,586311240 -1k6/4b2r/p2p3Q/Ppp2pP1/R7/R2K3b/1P2r2P/2B5 b - -,32,836,25445,690564,21160975,592558205 -3rk3/1q1b2b1/3pp2r/1pp5/2n3np/1P1PB3/4N1P1/1R1B1KR1 w - -,24,1155,25157,1168595,27015735,1227835174 -8/8/4P2n/P2N2P1/4k3/K2b3p/8/8 b - -,17,271,4835,71175,1312329,18736060 -r2r4/p2k2B1/P1b5/1PPPbq2/B7/2n3P1/1P5P/1N2KR2 w - -,28,1231,32605,1382400,36741025,1521292920 -5r2/1pk2p1p/3ppn1b/6BP/P1pQ2B1/3P1n2/2K1P3/R3q1NR b - -,48,1726,70841,2588455,102382090,3780245446 -1n1K4/3bB3/2k5/2p5/8/8/3p4/8 w - -,6,99,933,18767,179086,3904551 -4kbr1/1b1n4/3rn3/1pB1p1pp/pPpP4/P4PPN/4P2R/RNK2B2 w - -,24,858,21993,777942,20687084,727736005 -1rbk1r2/p1p1p2p/Qp1n3b/1n1pP1p1/1Pq2pP1/P2PBP2/1N2N2P/2R1K2R w - -,41,1609,60336,2302067,84267464,3154738459 -8/4rk1p/1Bbb3P/3p4/p1p2P1r/1B4p1/2R5/3K4 b - -,42,991,39902,911577,35252601,789557921 -2R5/1N6/3p1P1k/8/6n1/r1K5/7p/3b3n w - -,5,150,2956,81361,1492077,41658561 -k5n1/3N4/2P1K3/rp1P3p/1p2R2P/1P6/2R5/6q1 w - -,32,912,25126,676758,17521306,471995406 -8/7b/2B1Pk1N/Pp3P1K/1B4P1/n7/1r4bR/8 b - -,23,614,12798,337897,7223971,192684330 -3q1b2/5b1N/1pk3p1/2ppQ3/2Bp3P/P1P5/2NK1PP1/1Rr3R1 b - -,31,1528,40472,1854380,50691981,2192374276 -1k6/8/Pp4P1/2p3R1/2P1r3/6p1/6B1/3K2N1 w - -,20,313,6795,97076,2247800,32715667 -8/7k/5n1p/6p1/1p1PR3/2Q2Kp1/p1P5/6R1 b - -,20,707,12979,445295,8123417,276053349 -1r3br1/p1nkp1pp/7n/1pp2p2/5Q1P/2PpR2K/PB1N4/RN3B2 w - -,42,988,39938,939173,37168230,892289162 -rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -,20,400,8902,197281,4865609,119060324 -5B2/3n4/6k1/8/1K6/2N3Pp/2b5/3r4 b - -,31,529,15861,263223,7751097,129300529 -8/3k4/8/6b1/8/4b3/8/5K2 b - -,23,74,1737,8749,204235,882858 -r2B1qr1/p2bbk1p/np2p1pn/2p2p2/6PP/PP2PP2/1R1PQ3/2B1KBNR b K -,31,893,28530,876293,28856058,928682175 -8/1k6/1B6/5Ppp/PRr4P/6K1/8/R1q5 w - -,26,593,12792,331241,7307130,201413018 -8/7P/4k1P1/4P3/1Kb1B3/8/3B4/8 w - -,29,301,8493,93367,2661761,29187303 -6n1/2prk2r/P6p/P2p1pP1/1n1PP2P/1P2K2b/B7/R1B2qR1 w - -,18,689,10743,405499,7161030,267458043 -5k2/8/8/6b1/4Kb2/8/8/8 b - -,19,100,2094,11560,240688,1373445 -rn4r1/p2k4/b1p2ppp/qp6/1P2PpP1/1P4nP/P1KPN2R/R1B2B2 w - -,25,809,20287,630929,16079874,492821574 -rnk4r/1b1p2b1/1P6/pP2p1p1/2PpPP2/7p/3N2PP/1RB1KB1R w - -,21,579,13291,364465,8982266,248413220 -1r2kb2/p1Q1p2R/n7/3bn3/pP1pp3/B2N1N2/5Pp1/1R4K1 w - -,52,1495,70471,2000477,90435914,2584217936 -rnbqkbnr/ppp1pppp/8/3p4/P1P5/4P3/1P1P1PPP/RNBQKBNR w KQkq -,30,860,26505,785113,24890414,765915099 -5NB1/P7/7k/8/1p4K1/7p/8/5r2 w - -,18,310,5830,95402,1978980,32152139 -1r4rk/1p6/n7/B2pp1p1/P5KN/1p4P1/2q3nP/RN4b1 w - -,20,965,17940,837242,16630421,762608864 -1n2kb1r/2qbp1pp/rppp3n/p4pN1/P1PP3P/1P2P3/3N1PP1/R1BQKB1R w KQk -,34,678,23235,504508,17642950,413383648 -3nb3/5k2/4p3/4P2p/Qp2P2P/8/3K2B1/2N5 w - -,29,316,8505,112894,3024919,40736165 -rnbr4/1pppq1k1/1b2p3/pP4p1/P2Pp1np/1QB2P1K/2PNB1PP/1R4NR b - -,40,1179,44865,1395850,52005447,1667773530 -8/p3k3/P4q2/1N1p4/3P3p/1K5P/8/B7 b - -,25,325,7884,90101,2048523,23346396 -2b5/r2pn2r/1bnk2p1/pP1N1pQ1/P2p1P2/7P/2RBP3/4KBNR w K -,38,846,31445,723318,26619531,629691334 -r1b2b2/q2kp1rp/2p2ppn/pp1P4/2P1P3/NP6/P3NPPP/R1B1KB1R w KQ -,30,887,26588,818289,25046290,794669206 -7r/n1k5/p5B1/P7/1P5P/1PBr4/7K/2N5 b - -,33,745,21572,498036,13751707,319841077 -2Bb4/2r5/7k/3r4/4b3/2p5/1n2Kn2/8 w - -,11,555,5544,271673,2704405,129034970 -1rB2br1/1bN4p/p1p3k1/2P1p3/1P5R/3p1q2/PB2P3/3K1RN1 b - -,37,1439,46825,1794742,57649373,2170410318 -4Nk2/8/B3b3/6P1/1P5B/p7/6K1/6R1 b - -,16,413,5614,151692,2047776,57187792 -5Bq1/7r/1k2p1p1/p2n3p/P1p4P/2r2PK1/3R3R/5B2 b - -,33,964,30845,842656,27696947,740682514 -8/1pp2R2/1k4P1/1p1n1p1p/5P2/r6b/8/1N2K1N1 w - -,19,542,10206,269851,5230917,132852410 -1k6/8/1q1N3n/1QPPp1r1/1KP2R2/5Ppp/8/3R4 b - -,19,549,10812,318541,6854465,209250195 -6B1/8/8/8/7k/1p1p1K2/8/8 w - -,11,56,730,5198,69538,634670 -8/4k3/1Pr3P1/pR6/4B3/K7/8/8 w - -,26,480,11872,197740,4838631,79063957 -6B1/k7/8/2P5/1p1n4/3N4/8/1K6 b - -,13,243,2831,50250,556161,9901646 -2b2bn1/r1ppqp1r/3kp1p1/pp5p/1nP1N3/P2P1PP1/R3P2P/2Q1KBNR b K -,2,76,2449,84386,2761195,92591843 -3k4/8/2r5/3BR3/p6p/3K2b1/5P2/6r1 b - -,31,849,25668,658743,20043965,487754538 -rnbqkbnr/1p1ppp1p/6p1/p1p5/P1P2P2/3P2P1/1P2P2P/RNBQKBNR b KQkq -,21,529,12730,343365,9117006,259912909 -1Nk5/4n2p/4PppQ/6PP/4P3/2p2q2/b2r4/1RB1K1R1 w - -,25,1027,22583,870486,21228081,787747869 -r1bk3r/p1p1p2p/Qpqn3b/1B1pP1p1/1PPn1pP1/3P1P2/PN1B3P/1R2K1NR b - -,36,1072,36846,1130632,38619728,1213740061 -8/5k2/5n2/1KBN4/8/6Pp/2b5/8 w - -,26,590,13033,270616,5619873,112254558 -8/8/2k5/3bb1P1/2P5/1p4p1/1N2K3/NR6 w - -,20,485,9111,212958,4134019,94654324 -1N6/6P1/6k1/3b4/r2p4/3P3K/1N6/QR6 w - -,23,579,15351,337036,10141404,206725402 -2k5/8/8/8/B6b/3n4/8/5K2 b - -,19,186,3305,37066,667377,7835117 -r3qbn1/4k1p1/B4n2/1p3p1r/p1ppPP1P/P1P1Q3/1P2b3/RNB1K2R b KQ -,40,1082,42274,1191891,47109958,1373186471 -rnbk1b1r/pp1pp2p/2p5/1q5n/P7/Q1Pp3n/1P1PN1KR/RNB5 w - -,22,742,16190,547406,13182895,449402466 -4r3/n2k2b1/p2p4/P1pP4/2K5/P3Q2N/3BB2R/8 w - -,37,914,33878,783287,29500916,663115309 -r1b3nQ/pppk3r/3p1p1b/3q2pp/4PpnP/NPP2PPR/P3K3/2R2BN1 w - -,24,895,20973,752791,19442231,685288575 -6k1/7R/4N2B/Pp1pP2P/b7/3pP3/3K2P1/8 b - -,6,159,1234,30583,251805,6132073 -rnbk1b1r/pp1p3p/2p1p3/1q5n/P7/1PPp3n/Q2PN1KR/RNB5 b - -,41,733,29212,573157,22204593,472663744 -5q2/k7/2B1P3/8/5Rp1/KQ6/6P1/4b3 w - -,7,166,6368,137139,5062803,113050367 -1r4nr/2p1kpq1/pQ4pp/1p1p2P1/PnPP3P/1B2P2b/1P2KP1R/R1BN4 w - -,36,1229,41265,1395628,46329470,1566550761 -3r4/1b1npkbr/p2p4/P1p5/6Pp/4P2N/5PP1/R1KNQB1R w - -,28,1072,32843,1191898,38950618,1365012657 -rnbqkbnr/p1p3pp/1p2p3/3p1p2/PP4P1/B4P1P/2PPP1B1/RN1QK1NR b KQkq -,35,710,24711,544797,19032671,452160773 -6nr/3r4/k1n5/Pp1p2Pp/1p1PP2P/1P3N2/4K3/RqN3R1 b - -,32,705,22712,482587,15949158,339314753 -rnbqkbn1/pp1pppp1/2p5/8/2P5/7R/PP1PPP2/RNBQKBN1 b Qq -,19,605,13678,424005,10777488,340848022 -rn1kqb2/NQ3b1r/1pp1p3/5Ppp/3PPP2/2p4P/PPB1K2N/1RB2R2 w - -,45,979,43787,1064359,47049123,1251329760 -2N5/3r4/4p1k1/p4p2/PN3Pp1/3b4/8/4K3 w - -,13,325,4194,99645,1302775,29857661 -8/3k1n2/1p6/5rp1/1K2R3/1Rpp1bP1/7P/6N1 w - -,26,718,17352,487626,11741767,329531651 -8/1K6/R6P/1k6/8/4b3/8/3b4 b - -,21,359,6790,113291,2164549,36733489 -r5rk/1p2B3/n7/3pp1p1/P6N/1p3qPK/7P/RN4b1 b - -,51,840,35919,667974,28414999,580512944 -r1b1k2r/ppqp1p2/2nP4/2pN1Ppp/4p1P1/1Q5P/PP2PK2/R3BBNR w kq -,42,1153,46121,1220459,47631852,1249981508 -r7/1pp2nr1/pk1p1p2/1P2P1bp/5p1P/N1K2PP1/P7/4nbN1 b - -,39,647,23866,390034,14505339,240030556 -8/P2n2k1/4p1p1/1p5p/5R1P/6r1/8/4bK2 b - -,29,505,14170,262136,7205423,140799179 -5k2/8/1P6/p2R1BP1/P4r2/6b1/1K6/8 w - -,32,625,16613,349266,8706517,183608927 -r1N2bk1/1b2p2r/2n3p1/pPpP1p2/1P3P1p/P3PN1Q/R4KPn/2B3R1 b - -,32,1191,37107,1376728,42916336,1594513487 -r4bk1/1b2p3/1Nn3p1/pPpP1p1r/1P3P1p/P3PN1Q/R5Pn/2B1K1R1 w - -,39,1304,49801,1620287,61983191,1987842604 -rn4k1/7q/1p1Bp3/pp1p1pp1/P4P2/3Q1b2/3K4/N5N1 w - -,35,1231,41769,1369685,45104557,1443372333 -3R1n2/7p/r4k1P/p1p4P/K7/4Bp2/8/8 b - -,16,366,5706,124179,2081680,44290234 -3r2nr/1b1p4/2n3pb/p1p2kp1/2p2N1P/P4P2/2K1P2P/5B1R w - -,22,574,11643,315508,6368493,178768737 -1bb1r3/3k3P/4n2p/2P1B2P/2N1p3/8/PR1P3N/4K3 w - -,39,848,32175,721107,26508622,618788631 -8/r7/8/1kN5/p2P4/P5K1/b7/R6r b - -,35,691,21423,410826,12137763,233404889 -4R3/6p1/8/6k1/b2K4/8/5n2/2q5 w - -,16,602,7380,258671,3211018,109417617 -r1b2b1r/ppN4p/2n1pkpn/5p2/P1p2B1P/2PP4/4PPP1/1R1QKBNR w K -,41,1084,44280,1173935,47464310,1287923586 -1n1q1br1/1b1kpBp1/2NN1n2/2ppP2p/P2P1p2/Br4P1/2P2P2/2RQK1R1 w - -,46,1534,66208,2156016,92348718,2976333871 -2k2b2/1p3p1p/r2pp3/4Qn1P/P1pP3B/R7/2K1P1B1/6R1 w - -,57,1398,70090,1670231,80317423,1887634292 -4kr1r/2pR2np/1B3p1n/Q7/PP3RP1/2p4q/4P2P/4K3 w - -,42,939,34081,818448,28746054,727413013 -rnq2b2/1b2pk1r/p2p4/2p4p/P2P1p2/4P1P1/K3NPP1/R2NQB1R w - -,29,1077,31978,1169937,36834377,1337673614 -N7/2B4r/5P1k/8/1pP3P1/P7/2Bq4/nKR3b1 b - -,36,981,33158,876176,29804259,792056634 -1k4n1/1p2B2p/3pp3/4Qp1P/2pP4/1R2b3/8/K5RB b - -,22,1113,21227,1011494,18427095,838047029 -4r2B/R1p3p1/2r1P3/P5k1/n7/1P1N4/1b1K4/7N w - -,23,815,16921,577005,12175689,404888402 -rnbqkbnr/pp2p1pp/8/2p2p2/N1Pp1PP1/P2P3P/1P2PK2/R1BQ1BNR w kq -,25,650,17346,481064,13425718,390562005 -3Nk3/p5r1/b2p3p/5P1P/1bBp2p1/P1nR2R1/QrP3P1/4K1N1 b - -,33,837,25220,705251,21416205,639535758 -8/k1K5/8/8/8/b7/5b2/3B4 b - -,17,167,2990,33108,607957,7097194 -2n5/8/6kB/1KN5/6p1/6PR/2b5/r7 w - -,22,639,12795,330661,7046285,177781388 -8/6k1/1p6/3n1b2/8/8/7n/4K3 w - -,4,120,539,15152,64606,1724194 -r2k1b1r/4pP1p/p2q2p1/1p2p1P1/nP1p1P2/P1P3RB/3K2NP/RNB5 b - -,29,655,19641,486485,14916880,393395488 -5r2/1pk3r1/p2R1Q2/2p1Pb1p/R1K2pPP/1PP5/4N3/1N6 w - -,41,1173,44221,1153904,42779382,1072071415 -8/6k1/1p6/3n4/8/7b/7n/2K5 b - -,26,120,3048,17599,441084,2230739 -2k1r3/1R6/2nbN3/3p1P2/8/8/8/3K1n2 b - -,31,766,21323,453615,12565586,255551083 -8/8/6b1/k3p2N/8/b1PB4/K6p/8 b - -,21,361,8211,128257,3061565,47317841 -2bqkb1r/1r1p1ppp/ppn5/Q1P1p2P/2P2P2/4P3/P2P3n/RNBK1BNR w k -,31,1048,32970,1127707,36032647,1254033879 -1r6/2n2k1b/2B2B1p/8/6K1/3p4/4p3/R6R w - -,50,1676,69314,2132580,82354822,2475757012 -r1b1kb1r/pp2p1pp/n4p1n/2pp1P2/4P3/2PP3P/Pq4P1/RNBQKBNR b KQkq -,39,1046,36626,1030216,35847646,1040278460 -8/k3r3/6b1/p7/8/8/8/6K1 b - -,28,128,3508,16293,442804,2214952 -r1b1kb2/q3p1rp/2p2ppn/Pp1P4/2P1P3/N7/P3NPPP/R1B1KB1R b KQ -,36,1011,35811,1046510,37020528,1114143448 -5N2/P6B/7k/8/rp4K1/7p/8/8 w - -,20,193,3713,56096,1166889,18367665 -6n1/2P4b/4P3/P1k3N1/7p/K7/2N3P1/6R1 w - -,29,369,10968,159456,4803720,72859097 -8/7k/1p6/1n6/K7/8/4b3/6n1 w - -,2,40,165,3577,15525,345189 -5b2/k3Q2N/8/2pb2p1/2Bp3P/P1P3P1/2NK1P2/2r4R b - -,5,243,5729,235732,5620070,224106248 -4r1r1/1bN4p/p1p1B1k1/2b1pq2/1PP5/3p4/PB2P2R/3K1RN1 b - -,44,1763,68032,2681500,100336323,3895946027 -8/8/4n3/5k2/2K5/8/8/8 w - -,6,87,597,8295,52766,705164 -2k2b2/1p3p1p/r2pp2n/4Q2P/P1pP3B/3R4/2K1P3/6RB b - -,22,1255,27027,1401821,30767852,1488075165 -8/3R4/8/1k6/6PP/3b4/1K6/8 b - -,17,356,4905,98651,1256790,24032274 -2R5/6n1/8/5k2/5p1p/r2p3P/3n4/2Kb4 b - -,32,458,12620,165549,4507263,57825166 -r1r5/1kp1qp2/6p1/p1pPpP1p/P3P1PP/7B/1PQPKR2/RNB5 w - -,32,865,28409,773135,25786077,709988467 -r3k3/7p/8/1pn2pp1/2r3PP/5K2/7R/8 w - -,17,608,8949,322512,4800610,169837332 -k7/8/4K3/8/8/2P5/8/7r b - -,17,135,2287,17362,296075,2073934 -1n3R2/8/3rk2b/2pp2pn/P1p2P1r/7P/1K4B1/1b6 b - -,30,600,16126,319345,9016732,177685228 -rn1qkbnr/1bpppppp/pp6/8/8/N4P1N/PPPPP1PP/R1BQKB1R w KQkq -,21,503,11627,288594,7246553,189449032 -1k4n1/8/1b6/2p1bP2/R2R2Pp/p3K2P/b7/1B1N4 w - -,32,808,23384,578656,16615826,412642615 -8/2R5/8/4kb2/8/8/5r2/4n1K1 w - -,16,436,6025,161706,2231443,58377168 -rnbq1bnr/p1pkp1pp/1p1p1p2/8/7P/N1P1P2R/PP1P1PP1/R1BQKBN1 b Q -,22,768,16784,574252,13260905,452051376 -r2nk1nr/p3p3/b1qp1p2/2p3Pp/pP3pP1/2PP3B/3NPP1R/R1QK4 b kq -,38,1104,42014,1265833,48090138,1493405064 -2r5/6kp/p4nB1/prpP2P1/P2N4/7P/3n1N2/2bK3R w - -,32,1135,34482,1202770,35174587,1217408645 -3rkb2/p1Q1p2R/n7/3bn3/pP1pp3/3N1N2/1B3Pp1/1R4K1 b - -,33,1622,47219,2213774,64139358,2915305919 -rnbk1r2/3p3p/2p1Q3/p1b4n/PP6/2Np2qn/1R1P3R/2B4K w - -,40,1914,59010,2694444,80605158,3581584645 -1r4nr/2p1kp2/pQ3qpp/1p1p2P1/PnPP3P/4P2b/BP3P1R/R1BNK3 b - -,44,1344,49139,1480083,53940679,1636805679 -8/2k1N3/6P1/b6n/8/p4NK1/8/8 w - -,6,96,1668,28564,474143,8461624 -1rbk2r1/1p5Q/p1pb4/1q2P2p/P4pnP/1PP2P2/3K4/RN4NR b - -,39,1152,40175,1143772,40323970,1145951169 -rnbq1bnr/ppp1pk1p/6p1/3p1p2/PP6/2NP4/2P1PPPP/R1BQKBNR b KQ -,29,865,25959,782053,24110185,737840939 -6r1/rkp5/5pp1/p2P1P1P/P1P1P3/1P3p1q/N1K3R1/1RB5 w - -,32,960,29409,888973,27064332,826564899 -8/r3b1kB/8/7n/3p4/2p4r/1n3KbR/8 b - -,48,608,26838,384773,16817245,259589576 -7k/3b1R2/8/2p2PPP/8/8/6K1/8 b - -,9,159,1412,24740,231421,4123763 -5kn1/2n3r1/6r1/1P1Pp3/3B1P1P/2pP4/2Q2KR1/1N6 b - -,30,1010,30328,1053898,31315365,1110162403 -4k2r/B1p2r2/5p1p/Q2R3n/PP4n1/2p4q/4PR1P/4K3 b - -,29,912,26463,831616,25121323,795399866 -8/3P4/p1R4k/P2Q4/N7/7B/4p3/4K3 b - -,2,102,337,15628,56978,2477491 -4rNk1/2n5/8/8/P1BP4/KPp2P1p/3Q3P/7R b - -,6,233,3794,132646,2404761,81552680 -rnbqkbnr/pppp1ppp/8/4p3/5P2/P7/1PPPP1PP/RNBQKBNR b KQkq -,31,597,18646,399908,12718221,302128389 -2rk2n1/5b2/p2p4/P3p3/1Rp1PP1p/2K4N/B3Q1P1/3N2R1 b - -,19,744,15091,574544,12045451,458643679 -1b4r1/5P2/8/2P3k1/1p2B1P1/8/5K2/6R1 b - -,19,646,12602,381855,7501015,216440869 -3N3k/B4P2/n6P/1b6/3K2p1/6P1/8/2r4R w - -,24,567,13364,294812,7206468,156974546 -r1bqkb1r/1p2n1p1/2npp2p/2p2p2/p3PN1P/2PP1P2/PP1NB1P1/R1BQ1K1R w kq -,29,927,28090,904102,28404510,929227278 -1r1k3N/1n1b3p/3b1Pr1/p1ppp2p/1p1P1PPP/2P4R/2K1B2B/8 b - -,32,900,27395,746689,22548639,609140404 -r2q1bnr/ppp1k2p/2np1p2/4p1p1/P5b1/1PP3PN/3PPP1P/RNBQKB1R w K -,20,681,15958,539873,14005452,473585716 -1rbqkbnr/1ppp2pp/p3p3/5p2/3P3P/2P1P1Q1/PP3PP1/RNB1KBNR w KQk -,37,993,36969,1003011,37414249,1039309281 -1r2kbr1/p3p1pp/n7/1pp2p2/1QN3nP/2PpR3/PB4K1/RN3B2 w - -,36,889,30787,774052,27024645,693180717 -8/8/PP1kN1P1/8/3p1pR1/3P4/8/1r1b2KN w - -,22,438,7135,142844,2712669,54527323 -rn1q1bkr/1b1pp3/p7/2p2p1p/P2P4/1pN1P1p1/4NPPP/R1KQ1B1R b - -,32,924,29436,886375,28888918,910652740 -1rbqk2r/p1p1pn1p/Qpn4b/1B1pPpp1/N5P1/5P2/PPPP3P/R1B1K1NR w KQk -,32,681,22541,530115,17911447,461142665 -r1bqk2r/3pbppp/ppn2n2/2p1p2P/QPP3P1/4P3/P2P1P2/RNBK1BNR b kq -,29,986,28742,972211,29283556,992757273 -6r1/8/5k1p/rp6/6pP/8/2n1K2R/8 b - -,33,322,9879,114875,3561498,44966110 -5N1k/2r5/1N1Q4/6n1/P1BP3p/KPp2P2/7P/7R w - -,46,822,36873,618300,27066324,452613325 -k5B1/4N3/4n3/2P5/8/1p6/8/1K6 b - -,12,167,1596,25057,242741,3956287 -1R6/7k/R3b3/2p2P1P/6P1/8/rr5p/7K b - -,28,641,16310,345849,8807395,185944425 -4B3/7k/8/P3P3/8/5N2/6K1/2N5 w - -,27,112,2964,11627,302164,1307525 -1k6/4N3/6P1/b3N2n/8/p7/7K/8 b - -,16,264,3986,66521,1101718,18507512 -B4n1k/8/3b2p1/4p2p/7P/8/7K/8 b - -,14,160,2443,30948,498177,6480771 -4k3/3n1p1p/2Pb2r1/p3p1R1/1P1r4/pRPNB2b/5PBP/3K4 w - -,32,1188,40258,1477938,52224719,1887999012 -2b1qbn1/4r1kr/ppnp3p/5ppP/P5P1/1P3P2/2PPPR1N/1R1QKB2 w - -,17,593,10843,385258,7702873,274759274 -2qk3r/1pN2pbp/3ppn2/r2n2pB/PPp5/3P4/1BQ1P2P/R3K1NR w K -,42,1523,62436,2360849,95038871,3651112708 -rnb3r1/1p5p/4p1kb/p1P1np2/P2QNPPp/2P1N3/4P2B/1R1K1B1R b - -,29,1212,33785,1406837,39276211,1627711952 -6r1/8/k7/8/3P4/P4K1R/8/3N4 b - -,19,348,5903,124114,2024653,43817845 -rn1q2nr/p1pbkppp/3pp3/1p6/1b1P2PP/2N4N/PPP1PP2/R1BQKB1R w KQ -,25,696,18548,530445,15291018,447520000 -8/8/2P4k/8/K7/7p/2Q5/8 w - -,25,106,2811,16661,447189,2789759 -1n1rkb2/1q1b4/2Npp1rp/1pp3p1/2n1P2P/PPPPQ3/4N1P1/1RBB1K1R b - -,31,1188,37951,1458071,47493366,1832181057 -2b3n1/3N1k2/1n1P4/1PN2P2/p5p1/P1R1K3/1r6/4b3 b - -,29,530,15076,298523,8663001,178221352 -2q1k1nr/1p3p1p/3pp2b/r2n1PpB/PPp5/N2P4/1BQ1P2P/R3K1NR w Kk -,41,1426,57682,2001000,80090543,2770592190 -r1r4k/1pP1n3/1P2p1p1/5p1p/R4P1P/6b1/2K5/7b w - -,19,558,9507,295666,4867621,155465748 -4k3/K3N3/p1r5/p7/P3N3/8/8/8 b - -,18,296,4479,70053,1057988,15929348 -k7/8/2b5/p3r3/8/8/7K/8 b - -,27,87,2213,9521,243652,1040802 -1nq1k3/r4N2/P2P4/R4P1p/1P3K2/2Rp1P2/8/5B1q w - -,35,1091,30556,997266,26245591,898148628 -r7/n6r/3P1k2/pP3pp1/P1b2PPp/b3P3/3R1Q2/4KR2 w - -,23,903,23722,897945,25253950,932495811 -rn1qk1r1/4n2p/1p2p1p1/8/P3P1P1/7P/3bRKbR/1r4N1 b - -,53,609,31821,451256,23343178,376736151 -rn3k2/p6p/2p5/1r2Bp2/1b4PP/8/5PR1/K7 b - -,27,546,14238,266293,7213669,136834291 -8/5n2/k2P4/1p6/1p3K1P/rP1R1R2/8/3N4 b - -,15,324,5051,122005,1994476,51836289 -r2k1B1r/4p2p/1n4pb/pp2p1P1/1PPq1PBP/P2p2R1/3K2N1/RNB5 w - -,31,1050,27930,955651,26245702,904010458 -3K1k2/8/8/8/1P2n1p1/6r1/8/N4N2 w - -,10,181,2082,41659,519321,10776074 -5N2/P6B/7k/8/1p6/6Kp/8/1r6 b - -,14,253,3922,77054,1247124,26304786 -8/8/1k6/3n4/1K6/6p1/4r3/8 w - -,4,116,375,10232,40743,1073664 -1r1k2nN/6b1/3p4/1q1Pp3/4RpBp/3n1P2/4K1R1/8 w - -,22,767,16159,593510,13634447,508114784 -4B3/8/7B/4P1P1/ppK1k2q/PP6/8/R7 w - -,24,393,8158,160641,3619908,73486670 -1r2kb1r/4p1pp/2p2p2/p1p2n1n/q1P1PP2/7N/R2PK2P/1NB2B1R b k -,35,657,22768,459128,15914151,344494244 -r6r/2k1p1Bp/1n4pb/pP2pBP1/1P3P1P/P2p2R1/5K2/RNB5 b - -,32,1175,33959,1219673,34243526,1213498050 -2n5/3r2R1/5p1p/3k3P/P7/3P2bN/3B2K1/8 w - -,29,719,19826,472517,12563839,293107753 -rnbqkbnr/ppppp1pp/8/5p2/4P3/5P2/PPPP2PP/RNBQKBNR b KQkq -,21,563,12798,349811,8637221,241986719 -1R6/8/8/3N3p/5P1k/B5p1/3R2K1/3r4 b - -,9,272,3156,102102,1196126,39334465 -1B1k2n1/6b1/r4npq/5p1r/pP2PP1P/2P5/R2NR3/3K4 b - -,29,758,23120,632491,20300347,572216618 -2bqk1nr/p6p/n2p1P1b/p1pPp3/P5p1/1rP5/1P2PP1P/RNB1KBNR w KQk -,22,728,16628,569488,13541598,474338652 -n4kn1/r2B4/5pr1/1P1Pp3/3B1P1P/2pP3q/8/1NR1KQ1R w K -,38,1471,50494,1904297,65752307,2432867224 -3r4/4k3/1p2B1RN/1P5K/P7/8/8/b3b3 w - -,26,712,18295,474644,12002924,304784246 -1r2kbr1/2nbpp1p/5npB/ppp5/PP1P4/1RP4Q/5P1P/2NK1BqR b - -,40,1330,52970,1829431,74162292,2615622994 -1rbq4/p2pn1p1/P1p1p3/1pP2rk1/PB4Pp/7P/R2PR2b/1NQ1K3 w - -,28,1017,27933,969781,27737747,940647105 -8/r5k1/6B1/6bn/2np2r1/2p5/6b1/3RK3 w - -,17,891,14339,721283,12154934,590252046 -3r4/8/6KP/5n2/7k/2p5/5p2/8 b - -,29,134,3871,18693,511544,3065899 -8/P1n1kB2/8/7R/1p1N4/4K1nP/8/2R5 b - -,19,801,12731,530552,7821560,321053097 -8/5n2/7k/7p/7p/4P3/1R6/1B4K1 w - -,26,208,5211,46793,1100570,10674827 -7k/3n4/1p5P/1P1p2Bb/4r1R1/6K1/2bp2B1/8 w - -,21,654,14167,435114,9993751,306434505 -8/3b1k2/1N1P1n2/1P3P2/p3N1p1/P1RK4/r7/4b3 b - -,31,661,18792,402622,11236480,242991886 -6n1/2P5/3k2P1/8/8/p4N2/1r6/4b2K b - -,32,454,12230,170429,4216711,68540903 -2k1rbn1/3R4/2P5/3p1P2/3N4/6n1/2K5/8 w - -,25,574,13030,301401,6573073,156834585 -8/5rP1/k1q5/4R3/6K1/7p/5B2/8 w - -,32,1175,27415,905432,21340234,684365027 -1rbk1bnr/pp1p1ppp/n4q2/2p1p2Q/P1B1P3/2PP3P/1P4P1/RNB1K1NR b - -,31,1153,34800,1292844,39133555,1452419167 -8/3k4/8/4P2P/5K2/8/3N4/8 w - -,15,105,1528,8370,122233,721887 -8/6Rr/2k2p1p/1n2b2P/P4N2/3P4/4K3/4B3 w - -,35,750,21681,475962,13033576,295555241 -7R/5k2/8/2PP4/1K2p3/5rp1/6p1/8 b - -,19,381,7227,128697,2567429,43360805 -8/8/3k2N1/1K5P/8/8/3r1p2/6b1 w - -,13,233,2361,52168,519750,12976697 -2k5/8/1b6/4N3/7b/8/2K5/8 w - -,16,324,4453,85917,1056242,20548725 -8/1p3k1p/7n/2r3p1/1KppB3/2Rb2PN/7P/6R1 b - -,27,793,20094,588471,15156840,447720460 -8/1k6/8/2P1Bp1p/8/8/4N3/7K w - -,23,172,3376,20980,393058,2550571 -rnbqk1nr/pppp2pp/4p3/5p2/2P5/b7/PPQPPPPP/R1B1KBNR w KQkq -,26,818,22431,712453,20322900,654337104 -b6r/8/3N4/p1q2B1k/2P1PP1p/3K4/P7/R6r w - -,26,969,21258,784700,17706157,649455934 -7B/1Pk5/8/2P2p1p/N7/8/5r2/7K b - -,17,238,3564,57147,868027,14988875 -b6K/8/7k/6r1/2n5/2p3b1/8/2r4n w - -,0,0,0,0,0,0 -NQ6/8/6Bk/8/5r1K/1p5p/8/8 w - -,3,39,1083,16375,475047,7106636 -1k6/4b3/6P1/7n/8/2q5/1N5K/8 w - -,8,331,2805,104699,940746,33585421 -8/R7/1n1k4/1p4r1/6p1/1K6/6r1/8 b - -,30,469,13860,185397,5446448,72748446 -8/4N3/3pb3/8/3N1k2/8/3K4/3R4 w - -,27,392,10679,141484,3910037,49685104 -r1Qr4/1k4p1/6p1/pn3R2/3PP2P/1P6/2P1N3/4K1n1 b - -,5,164,3975,117042,2911569,81260482 -5b2/5b2/3B4/Pk2p3/8/2P1P1Np/2n5/1K6 b - -,26,478,11790,204499,4930059,83220242 -1B3b2/r1r5/nP4k1/1P1BP3/6pP/1N1bK1P1/8/4R2R w - -,40,1375,51173,1710380,61981624,2043144150 -kr1b4/8/1p3R2/1P3p2/4p3/nB4K1/PN6/4R3 b - -,13,411,6750,207418,3946996,119705335 -r3k1r1/4n2p/1pn1p3/6p1/P3P1P1/3q3P/3R1KbR/1r4N1 b - -,65,876,51340,792288,43718322,734014624 -2k5/8/5N1n/8/8/8/3N4/3K4 w - -,18,149,2541,24871,416358,4218261 -1kn5/7P/p5r1/P1pb2B1/1P6/1PR2B1P/1N2K3/r6r b - -,47,1510,63870,2061204,82144876,2654404524 -8/8/5k1p/rp4r1/6pP/8/2n2K2/7R w - -,16,469,6640,190295,2741112,79086911 -r1k4r/p4pQ1/3p2pb/1pp2NP1/P2R4/7b/1PK4P/1nB4R b - -,29,1116,30654,1181520,33683017,1300780226 -8/p7/P7/5k2/N1KP3p/5q2/1B6/8 w - -,11,306,3622,89228,1123332,26940955 -8/6b1/7r/P3p3/1nk3Np/K1P1P3/1B6/1b6 w - -,11,296,3301,85445,976836,25005923 -4N3/5kBb/B3R3/1p4P1/1P1Rp3/p7/8/6K1 b - -,7,237,1719,58003,542187,18333230 -rn1qkbnr/2p1pppp/pp2b3/1N1p4/2P2P2/3P3P/PP2P1P1/R1BQKBNR w KQkq -,30,728,22432,573207,18136067,487799138 -rn4nr/4b2k/1R1pP3/1b5p/pP2PP1P/p2N2P1/2KB3R/1N6 b - -,24,687,17708,515951,14067963,417410872 -rn3b1r/1bq1pk2/p2p4/2p2p1p/P2P4/4P1P1/1rK1NPPR/R2NQB2 w - -,5,197,5135,201430,5582277,217543881 -k7/8/bb5P/8/4N3/r7/3Kp3/8 w - -,11,335,3365,104632,1019221,31939830 -2K5/6k1/8/8/1P2n1p1/4N1r1/8/5N2 w - -,16,324,5106,106590,1671491,35292648 -5kn1/2n3r1/5pr1/1P1PR3/3B1P1P/2pP4/2Q2K2/1N5R w - -,43,869,35113,817263,32462688,807165232 -3R4/k3n3/3P1N2/1p1RK3/1pq4P/1P6/8/7r b - -,36,711,23195,470507,14966140,318972686 -r4bnr/4pk2/5p1p/ppppqb2/PPPnQ1pP/N1N2PP1/R2P2B1/2B1K2R b K -,40,1290,50554,1727946,66509742,2351827500 -1rN2rk1/np2ppb1/1p3np1/1qp2b1p/PP5P/3P1PP1/4B3/1R1KR3 b - -,38,743,27830,579465,22465455,493931574 -3b2nr/1pq2k2/8/4pPpp/ppN3P1/B1P4P/P2pK1B1/5RNR b - -,34,1076,35494,1071320,36417465,1070279451 -1k6/5b2/8/3pn1p1/8/N2pn3/3K4/8 w - -,8,197,1493,35919,295992,6949389 -5R1r/8/2kN1P2/8/2p2K2/2PN4/7r/8 w - -,32,767,20170,464582,11660840,269104659 -3rkb1r/p4p1Q/3p1np1/1pp3P1/P2pP3/5R1b/1PK4P/1NB3qR b k -,44,1424,58317,1792782,71524747,2160228857 -r1b2r2/1p1p2k1/nbp5/pP2p1p1/P1Bq3p/2B1npPK/R1P4P/QN4NR b - -,50,1134,55446,1328245,63238046,1622659271 -2r5/1k6/pb4P1/PppR1p2/5B2/RPr4b/3QK3/8 b - -,29,917,25882,878771,24769285,868696740 -1n1r2kr/6b1/2b4p/p5R1/2p4p/4Pp2/2N2K2/5R1B w - -,29,841,22875,669506,18308377,550622759 -1n1qk3/5N2/2rP4/3K1P1p/1PR2P2/8/R7/2q1b3 w - -,33,1175,29029,1090847,24997344,966951147 -8/4rk1p/2b4P/3p4/p1p2b2/1B2B1p1/2R4r/3K4 w - -,24,1027,21112,841967,17007117,641414148 -bnk2r2/7p/8/R1Ppq3/P7/3p2K1/2NP3n/2B5 w - -,3,144,1898,82158,1176278,47323819 -k7/8/p1b5/3r4/8/8/4KB2/2Rq4 w - -,2,59,887,26589,442403,13127176 -3b4/5rk1/6p1/p3p2p/P1r1PP1P/8/Q2pK2R/1R1N2N1 b - -,34,1138,36126,1238630,36837436,1283487672 -8/1k6/7b/8/8/3K2pB/8/1r6 b - -,27,326,7932,94314,2316598,28260356 -rR6/8/2b1Pkp1/pp1p1p2/Pbq2P2/2p3P1/3B2P1/R2KN3 b - -,28,603,18085,389429,12332308,272223122 -8/7n/P5n1/2k2P2/1p3R2/1B5P/2KR4/6N1 b - -,12,437,5308,189013,2491617,87330979 -k7/8/r2P1pP1/p1p5/PNP5/1Pq2p2/8/1RB2KR1 w - -,23,530,10972,265367,5853744,144108808 -8/q7/R1b3Bk/1P3P2/p6p/8/8/1K6 w - -,17,431,7284,179829,3071708,79530463 -k7/2R1n3/1q1PK2N/1p5R/1p5P/1P6/8/5r2 w - -,24,748,17011,511834,11802813,348866876 -rn6/p2p2p1/1pp1pq1k/5p1n/PR6/N3Pb2/3K1PB1/2BQ2N1 b - -,34,1085,35944,1156448,37574367,1231835166 -8/7k/2R1P3/7p/4n2p/8/2B3K1/8 b - -,6,111,1241,26840,283542,6411298 -b1kq4/7p/2P5/1Rnp4/P1Nr4/3p3K/3P3n/2B5 w - -,23,680,12919,402262,7407392,241117216 -rn4n1/4b2r/3pPk1p/pb3p2/1P2P1pP/p2R2P1/2K1NP2/1N2B2R w - -,35,928,28468,793128,23389725,677213319 -k1bn4/8/1R3N2/5Pp1/8/K1pp4/7P/8 b - -,13,320,4365,102990,1556114,34644892 -8/rk4P1/5P2/8/7p/q1B4K/8/4R3 b - -,25,630,16918,435160,12543279,325718307 -k7/5n1p/P1bB4/3p1N2/8/3p3K/4q3/5n2 b - -,38,621,22569,346120,12302765,182879532 -1B1k2n1/2r3b1/6p1/4Rp1r/pPN2q1P/2P3n1/8/1R1K4 w - -,28,1155,27515,1145512,27370605,1139453049 -1B6/r2Nbr2/nP4k1/1b2P3/6pP/4K1P1/8/4R2R w - -,24,821,20397,702369,18470084,636201962 -8/8/P3K3/8/8/8/3R4/1b2k3 b - -,9,146,1544,26592,294811,5268625 -8/8/2P5/5n2/1K3k2/8/8/8 w - -,9,135,1020,14278,121487,1597143 -Q1bq1b2/6pr/1p1pkp2/2p4p/3p3P/N1P3N1/Pp3PP1/1RB1KBR1 b - -,26,943,24020,881898,23273290,863238862 -r7/2b3r1/8/2p1P3/P1N1b2P/1p1kp3/3P4/3K1R2 w - -,22,871,17442,663724,12921060,475510951 -8/8/b1kb2P1/8/8/1p5N/3K1b2/N5R1 b - -,35,597,18767,335753,10054504,190719823 -2k5/1N6/8/1Q1n3p/7P/3RBr2/2K5/8 w - -,42,713,27558,447796,17615450,288100486 -r1b1kb1r/ppp1pp1p/2nq4/3p2B1/2P1P3/3P1K2/PP3PPP/RN1Q1BNn w kq -,36,1592,48683,2059860,63278636,2633450368 -2r2k2/1p2p2p/7n/3p1Pp1/2PB2b1/6P1/4RN1P/2K2B1R b - -,24,864,21016,729851,18217443,622353088 -r2nk1r1/7p/1p2p3/5Pp1/P5P1/5N1P/3RK1bR/1r6 b - -,36,835,29316,698174,24774450,597172214 -8/8/8/3N3p/1R3P1k/B5p1/6K1/r2R4 w - -,34,217,6000,61409,1799469,20886221 -3r2k1/p7/PRP5/2P1B2r/2N5/5KP1/1P6/2qB4 b - -,38,994,37129,953378,34765414,881696927 -3b1r2/4k3/6p1/p3p2p/P3PP1P/1Q6/2rp1K1R/2RN1BN1 w - -,46,1140,40951,1012272,36996627,919685029 -r4b1r/1p1bnk2/1qnpp2p/2p2pp1/2Q1PN1P/2PP1P2/PP1N2P1/R1BB1K1R b - -,45,1782,75177,2963978,122154431,4802770826 -b4N2/8/1k6/7P/P4b2/r3p3/8/6K1 w - -,7,158,1252,32103,265796,6988930 -6r1/5R2/7k/8/n7/7K/6B1/1b1q4 w - -,24,986,18667,761303,14485721,589483251 -B7/5b2/3b4/1k2p3/8/2P3Np/2n5/1K6 b - -,30,477,12371,202322,4997277,83801521 -1r6/8/r7/k7/3P4/P1N2K2/5R2/8 b - -,24,541,12585,281379,6726231,150429237 -rnbqkbnr/pp1p1pp1/4p2p/2p5/7P/NP6/P1PPPPP1/R1BQKBNR w KQkq -,21,586,13952,397722,10426143,306486114 -7r/7p/3b2kP/pb1pP1r1/B1p2Pp1/2p5/6R1/3K2B1 b - -,30,753,20955,511603,14333268,344145863 -6k1/8/4P3/P3P3/8/7N/N5K1/8 b - -,4,64,285,4675,20230,348194 -5n1k/8/6p1/4p2p/5bBP/5K2/8/2r5 w - -,10,284,3076,84698,912492,24505289 -k7/1r6/p2B2Pr/Pp3Q2/1P1p4/3K3b/R7/8 w - -,44,809,30526,623385,22437999,491091080 -rn2qb2/N2k1br1/Qpp1p3/5Ppp/B2PPP2/2p4P/PP5N/1RB1KR2 w - -,38,926,36461,967481,38625028,1097763307 -1B6/5k2/8/1Pn5/8/8/5K2/1b2R3 w - -,28,554,13818,259346,6492104,118309573 -8/p7/P5q1/2K2k2/N2P3p/8/1B6/8 b - -,25,259,6315,72558,1746754,21267117 -1n3bnr/7p/8/pppQ2kb/3pP1q1/3P4/P1PK3B/RN4R1 b - -,4,160,4113,135952,3733616,123818355 -rqbk3r/pp1p1p2/3P2n1/2pN1Ppp/4p1P1/Q4N1P/PP2PKB1/R3B2R b - -,23,1026,23289,1022801,24075885,1041812257 -k3r3/8/1P6/3r4/6p1/3K3n/8/8 w - -,3,102,582,16090,99719,2778796 -1r4r1/1bNB2B1/p1p3kp/8/1P2P3/3p4/P7/2RK2b1 b - -,29,996,26679,880228,23991763,768153180 -r4bnr/ppp1kppp/2n5/1B1qpb2/1P1pP3/3P1P1N/P1P1Q1PP/RNB1K2R b KQ -,41,1586,61141,2244498,84609542,3020468733 -3k2b1/2p1r3/5b2/pN2ppPr/p1P4R/P2P1PR1/2K5/B3qBN1 w - -,31,1188,30119,1155917,29420167,1125967088 -2b4k/8/2Pp1r2/p1N2p2/P2Q1PPp/1P3n1P/3K1n2/R7 w - -,5,115,3621,85186,2673053,64653603 -1kN5/8/P7/1pr5/4r3/1p5K/1b6/8 b - -,39,286,9389,83602,2671289,24777399 -6bR/6P1/4k3/1P6/5B2/3B4/5K2/n7 b - -,9,344,3817,142753,1747814,63895894 -8/2r5/3Np1k1/p4p2/P4Pp1/3N4/8/4K3 b - -,21,381,6715,115700,1938673,31731495 -1R6/3k1p2/4r3/p5rp/1b2p3/p1PN3B/1R2KP1P/8 w - -,37,946,32757,870234,29373006,798053395 -r3q1r1/pkp2pp1/1p6/2NPpP1p/P3P2P/6P1/1P1PK1B1/RNBQ1R2 b - -,3,99,2152,71176,1651885,56086401 -5k2/5Np1/1p4q1/p4p2/P1RKPP1p/1b5n/7P/3R1q2 b - -,39,839,32889,705031,27779108,593831634 -2br3r/4R3/5P1k/2p2P2/5R1P/6Pp/7K/8 b - -,21,565,12122,310283,7247204,181504179 -1N6/8/3k4/8/4PK2/8/2p1Q3/1R6 w - -,39,356,10989,108879,3350766,37679896 -8/2Bk1b2/7P/P1K1P3/6P1/8/8/8 w - -,12,158,2077,23037,318046,3659048 -8/8/2k1p1B1/4P2p/4P2P/1K3N2/1p6/8 b - -,10,153,1577,22617,244466,3341839 -7k/1B3n2/4p1b1/pp2P2p/7P/Q2NP3/5K2/8 b - -,14,485,7615,248315,3997974,126360393 -rnbq1b1r/p2p3k/1p3p2/1P1pp1pp/3P1N2/P1P3nP/3B1K2/2R2B1R b - -,33,920,29921,832059,27342441,769596458 -8/7b/2B1Pk1N/Pp3P1K/1B2b1PR/n7/7r/8 w - -,22,483,10445,221246,5014166,107651666 -q7/3R4/7B/4PkP1/2K5/Pp6/8/8 w - -,26,621,11512,251614,4452256,96542316 -8/1Brk3N/p2p1b2/P2Qp1P1/7p/N1P4P/8/1R3K1R w - -,46,597,27214,419218,18774066,305841885 -rn3bnr/p1pBpk1p/5p2/1p4p1/4q1b1/N3Q3/PP1P1PPP/R1B1K1NR w - -,27,1068,34875,1250559,43618971,1506063664 -6nr/2r5/k7/np1P2Pp/1p1P3P/1P3N2/4K3/RqN3R1 w - -,26,831,17383,554804,11690964,385071826 -B4b2/p2k1r2/1P3p1n/P1p1p2P/2P2N2/2R2N2/8/4K2R w - -,37,657,24558,446645,16694504,314537803 -B4r2/4k2b/n6p/8/6K1/2Bp4/8/R2r4 b - -,38,978,33245,876272,29037850,774235763 -3n4/4Bk2/PPp2b2/1Nr3pN/8/8/8/6K1 b - -,25,506,11858,245958,5884571,123754455 -rnb1k3/1p1q1ppr/2p1pb1n/p2p3p/PP5P/3P4/2P1PP2/RNBQKBNR b KQq -,31,867,27797,779151,25928748,746822795 -6R1/rpp5/1kn3P1/1p3p1p/5P2/P1K2P1b/8/1N2n1N1 b - -,24,377,9222,157077,3805373,68934616 -r1bqk1n1/p2p1pp1/1prb4/3Np3/1n1P1PPp/2p1B2B/P2QP2P/RN2K2R b KQq -,36,996,34181,1025611,35917776,1139079392 -3b3Q/2Pk4/n7/7p/3p3P/6B1/8/1rRK4 w - -,30,457,14927,247000,8612065,150441103 -8/5r2/2kb1B1p/5p1P/P7/n2P1K2/4N3/5R2 w - -,30,832,23594,625109,17111516,444248358 -5N2/4r1k1/nP3b2/2R1P2P/3K2p1/6P1/4b3/4R3 w - -,29,675,18037,444307,11683113,298228262 -4k3/8/5P1r/5r2/8/2N5/5K2/4B3 w - -,5,125,1759,42589,643318,15887274 -8/7r/8/1p6/4k3/6p1/1K4n1/5R2 b - -,24,506,10897,190062,4089440,66402342 -8/8/8/1P6/1K6/7k/4N3/8 b - -,4,56,286,3801,20223,259772 -r2qkbnr/p1p2ppp/2n5/1p3b2/3pp1PP/PPN2P2/2PPP3/R1BQKBNR b KQkq -,43,1001,41787,1002742,41026679,1023707366 -4n3/R7/P1p1k3/6p1/r7/1PB3N1/2NK4/b7 w - -,37,736,23971,485800,15127092,315632930 -8/8/2P4k/1K6/8/8/4Q2p/8 b - -,8,232,2171,59187,676949,17144553 -8/8/4P1k1/P3P3/8/3N4/7K/6N1 w - -,16,94,1533,7710,127354,605072 -4k1rr/1ppR3p/5p1n/Q4n2/PP1B1bP1/2p4q/4P2P/4KbR1 b - -,40,1318,47216,1538825,55435599,1792861681 -8/7Q/4pb2/2B4P/k1RP4/8/8/1K6 b - -,3,99,1010,34010,336733,11898967 -r1bqkbnr/p2pppp1/np6/2p4p/1P6/3P1PPN/P1P1P2P/RNBQKB1R b KQkq -,22,654,16134,468178,12668286,371150086 -1R6/3k1p2/4r3/pr6/1b2p2p/pRP4B/5P1P/2N1K3 b - -,23,633,15234,437470,11136185,327625285 -rb4b1/r7/1p6/p1P1P3/P1N5/1p1kp2P/3P3R/3K4 b - -,24,387,9543,159754,4237329,73746169 -r1bqkbnr/pp2pppp/2n5/2p5/2PpP3/PQ5P/1P1P1PP1/RNB1KBNR b KQkq -,32,952,31262,888903,29627557,839159302 -3r1n2/6kr/7p/1R1b4/p1p4p/4PB2/N2R3b/5K2 b - -,34,1286,43042,1538584,52155233,1794828165 -8/4kb2/1b2P3/1P6/7P/p5n1/8/K3R3 w - -,14,347,4824,113175,1639843,37118265 -rnbqkbnr/1ppppppp/8/p7/2P2P2/8/PP1PP1PP/RNBQKBNR b KQkq -,21,463,10766,264710,6738000,180076757 -8/7k/4P3/8/4K3/5p2/8/4B3 w - -,16,90,1454,8774,137617,978282 -1nbqkb1r/3pp1pp/1pp5/4Pp2/rP1P4/pB3N2/PBPN1PPn/1R1QK2R w Kk -,32,738,23622,577406,19234379,495923477 -4r3/rkp5/5pp1/p2PpP1P/P1P1Pq2/4Q2B/NP1K2R1/R1B5 b - -,32,898,26241,806906,22687041,719395059 -1r1k1b2/p3p3/n1Q5/p2b1n2/1P1pp3/B2N1N1p/5PPR/R5K1 b - -,32,1552,44682,1998927,58843553,2520700462 -b4k2/4R2B/1P6/p5P1/P3P3/6b1/1K3p2/8 b - -,16,330,6020,116270,2324559,44523602 -n3k1n1/8/8/1P1P4/3P3P/2p4r/5KRB/1N4Q1 b - -,17,402,7016,194625,3666319,109956783 -1n6/2p5/1p3N2/2k2K2/1p3P2/8/8/8 w - -,14,145,1731,18272,217750,2426116 -rb4R1/8/1pr5/p1PbP3/Pp2p3/3k3P/3P4/1N1K4 b - -,26,501,13291,241871,6700328,121549264 -rk6/2p1r3/5pp1/p2PpP1p/P1P1P1Pq/3Q3B/1P1K4/RNB3R1 b - -,22,657,15708,477677,12255842,378334397 -8/1r1Bn3/3k1p1p/5PrP/P5R1/3P4/2NB1bK1/8 b - -,36,1041,32615,957059,28610987,839371828 -k7/4n3/1q1PK2N/rp5R/1p5P/1PR5/8/8 b - -,29,717,20137,484906,13868146,330642121 -4Q3/5Q2/1k6/8/8/3K3B/8/8 b - -,3,163,427,22906,67747,3571177 -5b2/r1B5/nP4k1/NP2P3/2P3p1/3bKBP1/5r1P/4R2R b - -,38,1160,42431,1288429,46179719,1413393391 -5kr1/5qBb/1pB1p1P1/8/p4P1P/N2R4/1P1N1Q2/5K1R b - -,4,222,4407,232095,5193095,260717517 -r2qkbnr/p1p2ppp/2n5/1p2pb2/3p2P1/PP3P2/2PPP2P/RNBQKBNR w KQkq -,19,811,16324,671745,14627325,590968180 -b5r1/1k4N1/p1p2nP1/Pp5P/1P4R1/1P3B1P/3r4/1rB1K3 w - -,23,774,16218,515146,11177316,345013362 -3r4/p1p3p1/n3P1kp/P1r2bP1/2Rb2P1/1P6/4N3/2K4N w - -,16,515,8886,299385,5681601,193596212 -6q1/2k4r/p3pnp1/7p/P1pP3P/4rPK1/3RR3/2B2B2 w - -,21,828,18490,704386,16955396,629539105 -r1b1kbnr/1p1p3p/6p1/p1p2p2/2q1PB2/P4N2/4KPPP/R1Q2B1R w kq -,5,177,5912,199964,7029180,233382735 -1k1r4/2b5/p7/Ppp2pP1/3R1B2/3K3b/RP5r/6Q1 b - -,29,833,23532,690585,20014644,604689177 -6br/3n3k/1p4RP/1PBp1p2/6N1/1p1p4/6BK/8 b - -,14,411,5857,159487,2616631,70062446 -rnbqkb1r/1Bpppp2/pp4p1/7p/6n1/2P1P3/PP1P1PPP/RNBQ1KNR w kq -,33,847,25916,688509,21452953,597400095 -rnk5/pb4r1/2p3p1/1p3p1P/1P2P3/1PB3RP/P2KN3/4rB2 w - -,30,737,20517,520050,14781740,385618144 -3knb2/p5r1/1P2B3/P1p1p1pP/1NP5/6R1/8/4KR2 b - -,19,782,14991,589382,11447743,435029324 -rnbk2r1/3pqpb1/1P1Np1Q1/p1p3p1/1P1PPP2/B6p/2PK2PP/RN3B1R b - -,31,1420,41371,1824142,53542536,2305190745 -r1b1kb1r/pp1ppp1p/1qp3pn/2nPP3/5PP1/P4N1B/1PPQ3P/RNB2K1R b k -,29,941,29782,968169,31886498,1050179426 -2b3r1/2Np3k/8/pr3p2/P1P2PPp/1P1P3P/RQ1KN3/4n1n1 w - -,36,1004,32099,892621,27751357,774371322 -r3kb1r/1p2pppp/1qn2n2/p1pp4/P1P2Pb1/4PQ2/1P1P3P/RNB1KBNR b kq -,42,1289,52928,1573356,63290508,1896986855 -4rb1r/pppk1n1p/5p1n/2p1p3/PQ1P1Pq1/BP4Pb/4P2P/RN2KB1R b K -,47,1214,51585,1471652,59182691,1788793536 -rn1k1b1r/Nqp1pppp/pp2b2n/3p4/2P2PP1/Q2P1N1P/PP2P3/R1B1KB1R b KQ -,26,975,24770,920485,24428414,905632599 -8/P7/4n3/2kR4/1p6/6nP/2B1NK2/6R1 b - -,4,174,2891,112162,1756611,67332233 -r3kbnr/p1qn1pp1/8/1ppBp2P/3P1Pb1/P3P3/1PP1Q2P/RNB1K1NR b KQkq -,43,1824,76218,3085274,128355299,5049028365 -8/1pkbQr2/p7/2p1P2p/R1K2pPP/1PPR4/4N3/1N6 w - -,39,544,19352,308249,10634567,178735114 -4k2r/4n3/8/8/8/1K1p2N1/6N1/8 b - -,20,335,7157,114490,2512109,39117433 -5R1r/8/2K5/7k/7p/p7/8/8 b - -,10,187,2529,45136,707501,12078774 -rn2kb1r/1bqpp1pp/p1p4n/3Q2B1/2P5/7B/PP2PP1P/RN2K1NR w KQkq -,48,1092,47520,1149963,47350843,1219241603 -8/7P/4k1P1/4P3/1K2B3/4B3/4b3/8 b - -,12,400,4224,132980,1429905,43308157 -8/1B6/8/1p1qk3/3p4/1p6/4K3/8 w - -,11,236,2332,54943,558376,13646443 -8/6B1/8/R1K1P1P1/P3qk2/8/8/1b6 b - -,29,333,10159,141380,4223208,65808387 -Nnb3nr/r1pp4/3k1pp1/pPb3p1/3p1P2/5Q1P/P2BP3/2R1KBNR b K -,25,974,24282,921004,23546968,883511910 -rnbqkbnr/pppppp1p/6p1/8/3P2P1/8/PPP1PP1P/RNBQKBNR b KQkq -,21,609,14069,418862,10554006,324970633 -8/4r3/k5b1/p7/8/8/8/6K1 w - -,5,140,667,17889,91482,2453119 -6n1/4br2/1r2kp1p/pp4BP/P5P1/N2P1P2/2p3BK/6R1 b - -,27,681,19178,485309,14310682,360548726 -rnbqk2r/2ppn2p/1p4p1/p1b1ppB1/1PP4P/3PR3/P3PPP1/RN1QKBN1 w Qkq -,31,860,26425,766330,24120469,727868806 -8/7b/p1P1Pn2/P1k3N1/7p/K1p5/4B1P1/3N2R1 w - -,27,520,14333,267894,7582842,140583731 -1k6/5n2/1p6/3b1rp1/6P1/KRpp3N/7P/8 w - -,14,378,5863,165952,2737759,77779011 -8/pr1pkNr1/b2b3p/1n1pB1pP/2B2P2/P5R1/Q1P1K1P1/1R4N1 b - -,25,1156,29314,1309651,34529635,1504713198 -1B6/4k1b1/2r2np1/5p1r/pPN4P/2PR1K2/4n3/2R5 w - -,36,1192,39986,1338700,44096137,1474722533 -1k6/1P6/8/2P2p1p/2N5/8/6r1/B5K1 w - -,3,43,739,10563,180150,2608865 -BN2rR2/8/6k1/6P1/2B5/8/K7/3bN3 w - -,38,728,25299,484676,16546413,318793453 -2bkrb2/5r2/p1n2ppp/2PppP1P/Q1p1P2B/NR3N2/P2P4/1R3K2 b - -,34,1490,44464,1989603,56671594,2542035255 -rnbqkbnr/pp1ppppp/2p5/8/8/1P6/PBPPPPPP/RN1QKBNR b KQkq -,21,563,13521,361756,9624190,264947279 -8/5k2/2P5/5p1p/8/8/4N1K1/B7 w - -,22,176,3656,23998,484078,3172492 -r1b1k2r/ppqp1p2/2nP4/2pN1Ppp/4p1P1/1QB4P/PP2PK2/R4BNR b kq -,29,1184,31329,1275842,33154697,1331106107 -8/7p/2R4P/3K1nkP/2r5/2p2p2/8/8 w - -,13,280,3399,70344,936406,19649163 -2bqk2r/1r1pbppp/ppn2n2/2p1p2P/QPP3P1/4PP2/P2P4/RNBK1BNR w k -,32,922,29711,858773,27813156,824733578 -5R2/8/3k2r1/1p6/2nK2p1/8/6r1/8 w - -,17,439,6636,180903,2591961,73304483 -b4k2/2R5/1P2B3/p5P1/P3P3/5p2/1b2K3/8 w - -,8,118,3481,51500,1350472,21240518 -8/4r2k/3NN3/p4p2/P1K2P2/6p1/8/8 b - -,13,250,3535,62282,919605,15066004 -7k/1pr1n3/rP2p1p1/5p1p/R4P1P/5bb1/3K4/8 b - -,35,391,14074,167327,5994813,74317975 -r1b3n1/3pqpbr/4Nkp1/ppp4p/1nPP4/P4PP1/3RP2P/2Q1KBNR w K -,34,1122,36182,1199204,39030162,1307984028 -1B3N2/1r4kr/nPR2b2/4P2P/3K2p1/6P1/4b3/4R3 w - -,31,804,23584,642425,18623515,524090390 -2N5/3N1n1k/3p1Q2/1p4r1/P1PP3p/1P3P2/7P/2K2B1R w - -,40,716,28848,486196,19437500,315904774 -5R2/3b3k/8/2p2PPP/8/8/8/6K1 w - -,17,134,2249,20076,351255,3339647 -rnbqk1nr/pppp3p/6pB/4pp2/7P/b1PP3R/PP2PPP1/RN1QKBN1 b Qkq -,28,907,26581,847050,25690641,819060993 -r1b3r1/1ppp2k1/nb2p3/pP4p1/P2qp2p/Q1B1nPPK/1RPN3P/5BNR w - -,29,968,28357,1022796,30845505,1172559902 -2k5/5b2/p7/Pr4B1/8/3p4/8/QRK5 w - -,24,585,15228,312247,8849200,170692861 -rb6/5b2/1p4r1/p1k1Pp2/PpP1B3/2R4P/3P4/1N2K1R1 b - -,29,936,26101,809039,22760867,691386323 -1r6/8/1k6/8/1K4p1/7n/8/8 b - -,18,91,2085,10276,243225,1363118 -b4rn1/p2k4/2qN3P/2P1p3/p1P2p1p/1Q1PRPp1/1K3P2/R4B2 w - -,41,1355,50445,1658139,59671035,1962616093 -rb6/5b2/1pr5/p3P3/PpP1p3/3k3P/3P2R1/1N1K4 w - -,17,435,7198,186885,3171862,85121857 -3bk2R/1N4r1/3r4/B2b4/p1Pp1p2/P2P4/4K3/6N1 b - -,5,144,4640,117784,3714207,93417523 -8/P5k1/4pnp1/1p1b1R1p/7P/2r5/3b4/5K2 b - -,47,663,27385,436687,16377338,286273079 -r1bqkbnr/pp1ppp1p/n1p3p1/8/3P2P1/8/PPPQPP1P/RNB1KBNR w KQkq -,30,716,22956,595259,19894900,552929252 -7k/1K6/5N2/1P6/8/3n4/8/8 w - -,17,167,2238,20198,243770,2363757 -8/P5kB/8/8/1p3K2/2r4p/4N3/8 b - -,21,411,7797,166204,3021486,67526280 -3N2bk/1nr1B3/7B/8/3K2p1/6P1/8/7R b - -,21,627,11248,325925,6520818,184747769 -b2r2r1/1k1n4/p1p1N1P1/Pp5P/1P4R1/1P5P/4K1B1/1rB5 w - -,39,846,26994,667283,19885644,529926130 -Bnbqk2r/2pppp2/pp4p1/7p/P2b2Q1/2P1P3/1P1P1PPP/RNB2KNR w k -,41,1046,41002,1047685,39977958,1038131217 -6q1/7r/1k2p1p1/p2n3p/P1p4P/B3rPK1/3R3R/5B2 w - -,30,1138,30842,1143282,30387623,1114128414 -6n1/5k2/8/8/8/1N6/6N1/3K4 w - -,15,145,2213,22240,354758,3664709 -rnbq2nr/ppppbk1p/2P1p1p1/5p2/8/1P2PP2/P2P2PP/1RBQKBNR w K -,28,862,23913,750076,21548757,685201138 -1B6/1r3Bk1/8/Pp6/4KN1p/8/5b1R/8 b - -,23,728,14764,461899,9440955,292742932 -1n1q4/p1B4k/P4P2/Bp1p2p1/3P3p/7P/5NR1/4Q1K1 w - -,40,707,28351,559043,22135532,457601396 -8/8/1K3k2/5P2/3r3p/p7/5b2/2R5 b - -,25,339,8578,121555,3084603,45081844 -1n1kn3/N1bb4/pp3r1p/3pp3/3pPp2/PPP2K1P/3BB2R/3Rq1N1 b - -,34,733,24309,546662,18509415,432511557 -6R1/p6k/P1P5/2P1rr2/7K/1P6/8/5B2 b - -,20,391,8933,166739,3831093,71492247 -5k2/6p1/3K4/8/b3pP1R/6qn/3N3P/3q4 w - -,12,489,7190,294358,4520838,184154813 -8/r1b3r1/1N2P3/2pb3P/P2k4/4p3/1p1PR3/3K4 w - -,17,700,11608,463155,8112779,313529366 -8/8/1k4pr/4p2p/P1R2P1P/2Bp4/6KR/8 b - -,9,246,2637,75714,975280,28458332 -1n2qbnr/4k2p/bp2p1p1/r1p2p2/P1p1N1P1/BQ2KP1P/3PP1B1/R5NR b - -,31,1094,33829,1152480,36314040,1215805162 -6k1/3P4/p7/P7/N6Q/2p1p2B/2R5/4K3 b - -,4,160,655,26425,112059,4463081 -1k6/8/1q1N3n/1QPPp1r1/1KP2R2/5Ppp/8/2R5 w - -,30,540,15892,317762,9660295,210636505 -8/3b2r1/rpk3N1/p4pR1/PpPpPb2/R1QB3P/3PK3/1Nq5 b - -,40,1039,38267,1037122,37881269,1060061022 -1nbq1r1k/2ppn2p/rp1P2p1/P4pB1/3N3P/5R2/P3PPP1/R2QKBN1 b Q -,23,978,23348,1016463,25868567,1142688977 -1Nk3nQ/7p/4pppb/3r3P/b1p1PqP1/5P2/P2P1K1R/2B4R b - -,45,1113,45270,1204805,46966414,1331293219 -6k1/8/1p6/3n1b2/8/8/7n/3K4 w - -,4,108,431,11064,49974,1248069 -5r2/1P6/1k6/8/K5p1/7n/8/8 w - -,7,132,1222,24270,261782,5161617 -3rkbr1/2pbpp1p/nN3npB/pp1p2q1/1P1P4/P1P4Q/5P1P/1RN1KB1R w - -,40,1488,54888,2034846,76163985,2834043248 -8/8/P7/2p5/P1PR1p2/2k2N2/6K1/8 w - -,24,130,2860,18948,417558,2468936 -rnbq2n1/1pQpk2r/p4b2/1N3pNp/4p3/3PP3/PPPB1PPP/1R1K1B1R b - -,25,1263,31479,1495399,40407452,1836786662 -1K6/R7/6b1/5q2/P6B/5k2/8/8 w - -,21,611,10564,329278,5956673,185641406 -6k1/8/P3P3/1p3P1K/1B2B3/n6R/8/8 w - -,37,213,7466,53603,1810506,14083763 -Qqb3r1/4b1k1/pp2p3/1Pp1P2p/P1K4P/3B4/2PNP2B/R1n1N3 b - -,28,911,26195,830250,24737106,783683024 -2B1k3/7N/1Q4P1/PN1p4/5b1p/1R2p1RP/4K3/6r1 b - -,19,760,11678,468223,7362419,298573735 -8/2k5/4p1B1/4P2p/4P2P/8/1K5N/8 b - -,7,112,668,10223,60041,913719 -rnbqkbnr/p1pppppp/8/1p6/6P1/N7/PPPPPP1P/R1BQKBNR b KQkq -,21,441,10202,234589,5912532,147577450 -k7/8/6r1/8/2p2K2/2P5/8/4N3 b - -,17,159,2607,26347,433908,4597043 -5b2/4k3/rp2bqN1/p4p1r/PpPpP3/1Q6/3P1PBP/RN2K2R b KQ -,6,228,7993,286832,10472297,363165364 -8/6p1/7n/R1Kbk3/8/8/8/8 b - -,24,287,5377,88134,1697466,28926743 -r7/n3b1kr/b1N3p1/pPpPpp2/1P1N1P1p/P3P2Q/5KPn/R1B3R1 w - -,38,1378,51932,1811444,68738441,2350284816 -8/8/8/8/3k4/8/5K2/1b2n3 b - -,18,95,1685,7835,142682,669311 -1n2k3/2q5/2rPK3/5PNp/1PR5/8/2Rq4/4b3 w - -,22,900,16987,723161,14446710,620519577 -2r5/pbk3r1/2p3p1/1pn2P1P/PP1N3R/1PB4P/3K2B1/1r6 w - -,27,1015,26499,1001199,27330857,1026970187 -BN6/8/3Pk2B/pp6/3K2Pp/P7/1P2P3/R7 b - -,6,222,1383,50388,328704,11860930 -r2b1qr1/p1B2k1p/1p2p1p1/2p1n3/P1bQPp1P/1P3P2/1R1P2B1/2B1K2R w K -,33,1139,35487,1204926,38648093,1312478574 -1n4nr/2k4r/8/Pp1p3p/Rp1PPqPP/1P3N2/7R/2N2K2 w - -,26,898,21492,746564,17568512,613410402 -6R1/3kNr2/4r3/1P1n4/6p1/8/1K4p1/8 b - -,39,851,30034,604944,20553909,397015177 -1r1rk2B/p4R2/P1P5/1nPP4/B4b2/N5P1/1P2K2P/2q5 w - -,35,1148,29680,998825,26328296,889475881 -5kr1/6n1/B2n4/8/8/2N5/8/1K6 w - -,19,301,5493,98244,1763271,38234289 -r1bqkbnr/p1pppp2/1p6/1n4pp/5P2/2P4P/PP1NP1PR/R1BQKBN1 w Qkq -,24,620,16959,468434,13986805,405596034 -1R3B2/p4k2/PN6/3r4/3pn1K1/5p2/8/4b1n1 w - -,19,597,12113,353877,7581107,215148953 -4q3/kB6/4P3/8/1R4p1/K1Q3b1/6P1/8 w - -,43,1005,38733,892567,32606325,757110160 -2n2k2/4p3/N3b3/p6P/4K3/4RP1p/5r1Q/6rn b - -,40,971,35403,901348,31582423,839579792 -6k1/3P4/p7/P7/N3p1BQ/2p5/4R3/4K3 w - -,38,165,6477,32322,1236271,6815294 -r1b1kb1r/p1qp1ppp/5n2/1pp3P1/P2p1B2/8/RPK1PP1P/1N1Q1BNR b kq -,33,1136,38237,1321476,45033261,1576857563 -3B4/1N1k4/7R/8/p1bprp2/P2P4/5KN1/6r1 b - -,27,741,19190,487776,12981359,324095934 -3N4/7k/7B/P2pP2P/bp6/3pP3/3K2P1/8 w - -,16,189,3125,33814,569462,6223151 -1n3k2/7p/2bn4/B1p5/P1PpPbKN/1p1P4/8/4R3 w - -,24,770,18276,558272,13293453,390154217 -rn1q1bnr/3kpp2/2pp2pp/pp6/1P2b2N/2PQ3P/P2PPP2/RNB1KB1R b KQ -,30,839,25287,743330,22844888,698863604 -3b4/2k5/2B5/8/2P1p3/2K5/6N1/8 w - -,19,186,3184,40252,679381,8627238 -k1r5/5Nr1/5P2/8/2pK4/2P5/6N1/8 b - -,20,267,5796,80510,1799798,25829268 -3rkb1r/p4ppp/3p1n2/1pp3PQ/P2pP3/R6b/1PKN3P/2B2qNR b k -,41,1284,50312,1516709,58567894,1760540836 -rnbqkb1r/1ppp1p1p/4p1pn/p7/3PP1P1/7N/PPP2PBP/RNBQK2R b KQkq -,30,990,31020,1046681,33767240,1161309060 -1n2Bbnr/p2r1p1p/1p3kb1/2p5/3pPBPq/2QP1K1P/P1P5/RN4R1 w - -,38,1157,38874,1175640,39807840,1208564525 -1r1k3N/1n1b3p/B2b1P2/p1ppp1r1/3P1PpP/2p3R1/2K4B/8 b - -,28,779,21244,563987,15543004,404271473 -b7/b1k1r3/7N/7P/P3p3/8/1K6/8 w - -,13,332,3878,98282,1166007,30083645 -R7/4Nk2/4b3/1P2p2r/pb3P1P/2n5/2K5/2B2R2 b - -,33,1022,32538,993938,31388206,957261751 -r3k2B/pRb5/P1P5/2Pr4/B7/N5P1/1P2K2P/2q5 w - -,27,1119,25578,968017,22809965,823884647 -1r2kb1r/p3p1pp/n4p1n/1pp5/1QN3PP/2Pp4/PB3K2/RN3BR1 w k -,33,715,23393,530730,17987938,423379414 -1r1r4/5bk1/7p/PBpp2n1/3PpK2/1P6/1R5R/B7 w - -,34,1052,31825,970075,28246746,853055216 -1nb4r/3p3k/1p3p2/rP1p3P/1p1p3N/5B2/5B1K/1RR5 w - -,37,825,30693,708946,26282108,630720192 -4k1Br/2p5/4pbp1/ppP1P1Bp/P2Q4/1PNR1P1P/5KP1/6R1 b - -,14,702,9381,447828,6089455,282328972 -rnb1kbnr/p1q1pppp/1ppp4/8/4B1P1/2P5/PPQPPP1P/RNB1K1NR b KQkq -,28,837,22536,699777,19118920,611385160 -rk3b1N/q7/1p1p1n2/1b1Pp1pp/1p2np2/2B2PPB/2R2K2/5R2 w - -,4,169,5278,218118,6943535,284464888 -B7/3Nk1B1/8/p7/1p1K2Pp/P7/1P2P3/5R2 b - -,9,393,3031,124041,899980,35240958 -N7/6nr/1p5k/5Pq1/2P3P1/Bp1B1N2/P1R4b/RK6 w - -,32,823,24283,670460,20368492,598238386 -6k1/8/n5P1/r7/1p1p1p1p/1P4nP/8/2K2b2 w - -,6,180,854,24969,117128,3388688 -1N1k4/6b1/P3p1p1/2PPr2p/R4B1P/8/2nKb2R/1r6 b - -,43,1065,40219,1026730,37457372,977802473 -5k2/8/b7/r1Rn1pP1/1p1p3p/1P4nP/K7/8 w - -,3,90,1121,30476,404805,10827740 -1n2kbr1/1b6/1B1r4/1p2p1pp/pPpP1n1q/P4P1P/4P1PR/RNK2BN1 w - -,19,854,16329,721861,14726428,642884845 -5k2/8/8/5p2/p2p1Qb1/6P1/5bP1/2BR1K2 w - -,23,288,7509,99556,2819629,39339107 -2k1n1r1/8/8/8/1K4n1/8/8/8 w - -,8,160,1015,22909,141544,3477390 -8/4k3/1Q6/p2p1pp1/R3bP2/4B1P1/6P1/4bK2 w - -,39,543,18370,274342,9039596,139956109 -6k1/7R/1P6/p2b2PB/P3Ppn1/8/1b2K3/8 w - -,23,529,10993,238423,4911240,103618545 -8/b1k5/4P3/8/8/8/4B1P1/Q2K4 w - -,30,341,10876,108925,3480898,37519099 -8/8/7k/8/8/6K1/B7/3n4 b - -,9,121,1165,15779,154490,2129782 -rnbqkbnr/pp2ppp1/2pp4/1B5p/8/P3P3/1PPP1PPP/RNBQK1NR w KQkq -,32,873,27875,788727,25350405,741162072 -8/5k2/3B1nb1/3N4/K7/6Pp/8/8 b - -,20,430,8250,164127,3183945,61811230 -rnbqk2r/ppppb1pp/4p2n/5p2/2P5/3QP3/PP1P1PPP/1RB1KBNR w Kkq -,30,868,26743,788234,24774597,747448248 -b1r3n1/p2k4/2qN3P/2P1p3/p1P2p1p/3PRPp1/1K3P2/3QRB2 b - -,31,876,27912,800872,26277620,774512350 -r4q1r/pb1k2b1/P1p4p/3Pp1B1/1PBP4/5NP1/1P1NKn1P/7R b - -,39,1458,53537,1922793,70051365,2446434138 -3k1B2/7p/7P/6rP/2Rp1Pp1/8/N1Rp2K1/2B5 b - -,22,648,12406,360700,6898343,202514597 -7k/5R2/8/2p2PPP/b7/8/5K2/8 w - -,20,167,3131,28902,542300,5216046 -2q5/2k1r3/p3pnp1/7p/P1pP3P/4rP2/3RRK2/2B2B2 b - -,40,713,27614,580038,21857167,512459795 -1nb4k/3pp1r1/5pp1/1Pp4p/5PPP/BpbqPN2/2R2KB1/1N5R w - -,35,1372,42334,1616096,50828680,1899227624 -r1b1kbnr/2q1p3/2n2p1p/ppppP1p1/P1P4P/NPN3P1/R2P1P2/2BQKB1R w Kkq -,38,1460,54442,1996053,74979634,2665163605 -1n2k3/rb1p2br/1PQPp1pn/5p2/pP2P3/5NP1/P3K3/RNB2B1R w - -,49,1388,63331,1861996,82586913,2487075154 -rk3b1N/6p1/qp1p4/nb2p2p/1pPPPpn1/RNB2PPB/4K3/7R b - -,31,1118,35984,1250740,41331781,1416401758 -r1bq1bnr/1p3k2/p1npp2p/5ppP/P7/1P2NN2/2PPPPP1/1RBQKB1R b K -,33,851,25250,668537,19819573,541383027 -7k/8/6KP/8/8/3B4/7n/6R1 b - -,4,95,588,12862,79107,1846410 -k7/8/4r3/8/2pK2N1/2P2N2/6r1/8 b - -,27,397,10475,152158,3991157,58412598 -r7/1pp2nr1/pk1p1p2/1P2P1bp/5p1P/N2K1PPb/P3N3/4nB2 w - -,5,198,3769,140774,2796395,102980250 -8/8/2Rb1k2/8/3p4/6pb/1B4P1/4K3 w - -,20,318,6228,118065,2305345,43953302 -5b2/3k4/6P1/8/5N2/1N6/2K2b2/5bR1 b - -,30,768,21214,527280,14002315,344669363 -6b1/r3k3/np5N/P2PPP2/6P1/6BK/b1B5/5R2 w - -,31,601,18059,386150,11508824,260831202 -1n1qnbr1/1b1kpBp1/2N5/2ppP2p/P2P4/B1r2Pp1/8/2RQK1R1 w - -,35,982,34810,1005045,36621284,1086550249 -8/7N/5r2/5k2/8/1P3P1p/3K3P/8 b - -,13,154,2328,25197,386638,4205339 -3r2k1/p7/PRP5/2PqB2r/8/5KP1/1PB5/8 w - -,6,225,5055,188532,4296868,157791111 -8/1k6/8/6b1/3K4/6p1/1r2B3/8 b - -,26,354,8837,109243,2762554,33927176 -rqb1k1r1/pp1p1p2/1N1P4/2Q2PN1/4p1Pp/P6P/1P1BPKn1/R4B1R w - -,47,768,33209,610455,25230505,521012351 -2Q5/1b6/8/1k6/6pp/8/r7/2K5 b - -,30,570,10927,230622,4523963,96502490 -r3k3/7p/8/1pn2pp1/4r1PP/4RK2/8/8 b - -,32,418,13625,194169,6534813,100015598 -b1k2r2/7p/2n1q3/R1Pp4/P7/3p2K1/3P3n/2B1N3 b - -,48,520,22014,280857,11313801,161521813 -1n1qBbr1/1b2p1p1/2NNk3/2ppP2p/P2P1pn1/Br4P1/2P2P2/2RQK1R1 b - -,40,1498,51887,1956603,65903645,2509133961 -4k1nr/2p5/pr4pp/1P1p1p1q/Pn1P1P1P/1P1bP3/3KR3/RBBN4 w - -,19,650,12933,449344,9392771,331664439 -1Nk3nQ/7p/5ppb/4P2P/2p1PqP1/1b3P2/PR1r4/2B1K2R w - -,25,881,22399,758890,21045625,704930293 -8/5n1k/8/8/7p/1P1K3p/8/7R w - -,18,211,3735,40193,724327,8358037 -2n5/1R5B/r1k2b2/P3p1pp/3P3P/2P1P3/4b3/B3KN2 w - -,32,729,21803,509994,14720753,355107619 -1n3K2/3k4/8/2p5/2bp3B/8/8/8 b - -,19,173,3075,31671,557921,6073807 -4k3/8/p2R3p/P7/5R2/2Q2b2/8/7K w - -,4,30,1596,13424,658601,6082984 -8/1P1n2k1/RB6/4nPr1/2pK3P/5p2/8/8 b - -,26,553,13508,325181,7822348,195343825 -r1b2b1r/2Bpk2p/1p2P1p1/p4pq1/P1p5/6P1/Q3KPP1/R3NB1R b - -,29,811,22548,693768,20264197,662605205 -R1b3R1/7k/8/2p2PPP/8/r7/6rp/7K b - -,31,524,12090,219413,5076860,98111228 -rn3rk1/1b5p/1p2p3/p1P3b1/P1P1pP1p/5n2/1Q2PKN1/3R1BBR b - -,35,1386,46790,1659619,56399169,1903618359 -8/P1n5/3k4/1R6/1p1N4/4K1nP/B7/2R5 w - -,48,664,25587,343112,13736799,186435886 -3k4/8/7P/2N1P3/8/5K2/8/8 w - -,18,78,1299,6240,99030,503962 -3N1B1k/B7/n6P/1b6/3K2p1/2r3P1/7R/8 b - -,27,705,16686,437053,10194305,269717341 -6n1/r2k1b2/p2p4/PR2P3/2p1P2p/2K4N/B5P1/3NQ1R1 b - -,21,749,14804,544998,11020693,417201549 -2k3n1/8/8/8/8/8/3N2N1/3K4 w - -,14,112,1712,16947,268837,2797138 -2rk1bn1/7q/5np1/5p1r/p1B1PP1P/2P1B3/1P2R3/RN2K3 b Q -,39,1347,50280,1709325,64721021,2183791373 -4k3/1r1bp3/N2nP1r1/p6P/4Q1p1/5P2/4K2P/3R3n b - -,33,1271,39094,1439409,43569122,1559740367 -3k4/1r6/p2p3p/Pb3P1P/1bP5/3p2R1/3R1KP1/8 b - -,25,540,12835,276570,6713011,146592951 -8/2k1b2r/p2p3Q/Ppp2pP1/3R1B2/3K3b/1P5r/R7 b - -,27,912,24456,815062,22434523,743931342 -r2k2n1/7q/3b1np1/5p1r/pPB1PP1P/2P1B3/4R3/RN2K3 w Q -,36,1382,49409,1886876,66700353,2561443652 -rnqk1b1r/N1p1pppp/pp2b2n/3p4/2P2PP1/1Q1P3P/PP2P3/R1B1KBNR w KQ -,30,689,21984,528517,17511753,442103483 -8/8/k2P2n1/1p6/1p2N2P/1P1R1RK1/8/2r5 b - -,24,619,12985,352297,6959408,194039087 -k5N1/5n1p/P1b5/3p4/6n1/3p3K/1q5B/8 b - -,45,565,22193,302419,11161344,157989403 -8/8/bK6/4P3/P3qBk1/8/5R2/8 w - -,23,729,14041,405393,7904707,221987870 -2R5/6p1/5n1q/8/8/1K3bk1/8/8 b - -,41,821,31977,543997,20215291,321102598 -8/8/2k1p3/1N2P2p/K3P2P/1B6/8/8 w - -,15,63,949,4544,71480,316882 -8/R2K4/8/P7/2b5/8/2q4k/8 w - -,12,396,4489,148521,1820940,58415094 -1k4r1/3n4/1p3p1b/pPN1p3/B7/2R4K/P7/2R5 b - -,28,785,18547,533515,12340720,358235258 -1r3k2/p2p2p1/1p1q3n/4NpP1/P1r1PP1p/1bp4B/1b5P/R4K1R w - -,27,1190,30554,1366466,34749533,1558761153 -rq5r/pkp2ppp/1pn2n2/3Pp3/Pb2PPNP/6P1/1P1PK1B1/RNBQ1R2 b - -,39,1327,48983,1670844,60848058,2100745175 -8/1B3n1n/8/P2p1P1p/1p6/1Pk4P/2p1R2b/2K2RN1 w - -,26,468,11450,199346,4921796,86601683 -7k/rp2B3/n7/2bpp3/P6N/Rp4P1/5rKP/1N6 w - -,3,99,1581,46619,884321,26312528 -rnbqkbnr/p1pppppp/1p6/8/1P1P4/8/P1P1PPPP/RNBQKBNR b KQkq -,21,610,14034,410437,10270936,311298889 -2k5/2P1P1b1/8/1p1pP3/1p3r2/8/4K3/5n1q b - -,36,259,7388,57305,1706116,15432334 -6b1/2r1k3/np5N/4P3/P2P1PP1/1P5K/b4B2/3BR3 w - -,26,630,16524,417263,11314650,289294990 -3k4/4R3/8/4b3/p3B2p/3K4/2r2P2/5r2 b - -,37,812,25437,572469,17382405,383173726 -r3k1nr/p3p3/bqnp1p1b/1pp4p/1P3p1P/P1PP1N2/4PPPR/RNQK1B2 b kq -,31,808,25081,674056,21250071,590071319 -8/8/6k1/1n1P3p/3n4/3K3p/1RP5/8 w - -,12,247,3690,73560,1177464,22344118 -4kbr1/1b1n4/1B2n3/1p1rp1pp/pPpP4/P4PP1/4PN1R/RNK2B2 b - -,33,988,32765,958150,32093810,934520182 -5k2/p1R3p1/1p5q/5pn1/P1N1PP1p/1b5B/1bp4P/5K1R w - -,30,1009,28287,977558,27052880,956550173 -3B4/1k6/8/5Ppp/Pr5P/8/7K/R1q5 b - -,39,540,19579,306256,10676343,182171972 -Rn5r/1b1k3p/2p5/p1Pp4/P5n1/2Npq3/3P3R/2B3nK b - -,43,893,34790,688447,25573848,510071155 -3k2B1/8/P7/PP3r2/3N3P/8/8/6BK w - -,22,344,7856,120086,2812969,42349790 -4k3/8/8/4n3/8/3p3r/1K1N2N1/8 b - -,22,361,8042,122486,2727083,41066942 -rnbqk1nr/ppp2ppp/3pp3/8/1b1P4/2N4P/PPP1PPP1/R1BQKBNR w KQkq -,22,722,17409,576820,15198298,506936440 -8/8/P4n2/2k5/1p3R1n/1B5P/2KR4/6N1 w - -,37,512,18911,254535,9086260,127460512 -8/7k/P2BP3/1p3P1K/8/6R1/1n6/7B w - -,36,230,7997,62510,2073813,17180489 -7R/7p/5k1P/1Kp4P/r4B1n/5p2/8/8 w - -,22,410,8480,158867,3372000,64361720 -3nk3/N3B3/PPp2b2/1r4p1/8/2N5/8/6K1 w - -,24,553,11534,267416,5502750,130007108 -k7/8/8/8/2pK4/2P1r3/4N3/8 b - -,14,98,1433,13554,210531,2093674 -b3k3/6b1/1N4r1/5np1/pBp2P2/4p1P1/6B1/1K4R1 w - -,34,1113,35252,1158966,35798866,1166408159 -6k1/8/3R1nBp/p2p2pP/1p1P2p1/6NQ/2P2K2/R7 w - -,44,466,18802,201857,8209323,87107819 -8/8/7k/KP6/8/6N1/8/8 b - -,4,44,281,3066,17267,196622 -6N1/N7/3p4/8/5k2/3b4/3K4/3nR3 b - -,21,413,7483,155491,2717264,58547232 -1n2k3/N1bb4/pp3r1p/1B1ppn2/3p1p1q/PPP1PK1P/3B4/5RNR w - -,28,957,21798,781406,17665440,649993969 -8/6k1/1P4B1/p2b2P1/P3Pp2/7R/4K2n/2b5 b - -,21,464,9188,184344,3700143,73417278 -rn3kr1/1b2pp2/1N4pb/pPpP3p/5P2/P3P3/RP1Q2Pn/2B1K1NR b - -,27,803,22061,698466,19918482,658582466 -8/Qb6/8/3k4/6pp/8/5r2/1K6 w - -,16,287,5535,95487,1948926,34075183 -r1b4R/8/4Pkp1/pp1p1p2/Pb6/2p3P1/R2B1PP1/3KNq2 b - -,30,791,23173,592183,18068757,460682143 -8/6k1/n5P1/r4p2/1p1p3p/1P4nP/8/1K3b2 b - -,29,96,2739,11882,339416,1521871 -1N1R4/P7/6k1/4r1b1/2B4P/8/K2p4/4N3 w - -,39,1106,39052,1085532,36098751,991795169 -rnbqkbnr/pp1pp1p1/2p2p1p/8/P7/3P2P1/1PP1PP1P/RNBQKBNR w KQkq -,29,553,15878,348681,10302571,251094524 -q4b2/1r6/5Pk1/8/1pP3P1/4B3/B1n1K3/2R5 w - -,29,980,24908,891855,21117118,763318253 -3kr3/1r5p/p6P/npp1p3/2PpK3/P3b3/RP6/N4BNQ b - -,30,686,20574,516546,15579603,421132833 -rR6/2b3k1/4b3/1P1Np2r/p4P1P/2n2R2/2K5/2B5 b - -,37,1208,42300,1343056,46063488,1442539185 -1r1qkbnr/pp2pppp/1Qn1b3/2p5/2PpP3/P6P/1P1P1PP1/RNB1KBNR w KQk -,30,880,26345,792849,23948550,740647551 -2N4R/1r6/p5k1/p7/P1p5/N3K3/8/1n5N w - -,26,512,12700,233687,5850670,105629081 -8/8/1P1k4/3n1Q2/3P3P/8/8/1N3K2 w - -,30,249,7118,61122,1764157,14978367 -rn4r1/p2kp2p/B1pB4/r3np2/P2b3P/5N1R/1P2KPP1/5R2 b - -,39,1428,51718,1868428,66598863,2366156904 -k5N1/5n1p/1qb5/P2p4/6n1/3p2K1/3P4/6B1 b - -,40,585,20842,305985,10278769,155614377 -3kR3/8/6r1/3B4/p4P1p/4K1b1/8/6r1 b - -,3,82,2149,48432,1317722,28968911 -2bQ4/6k1/1N4p1/1P1p1p2/Pp3PnP/3pR3/4PNB1/4K3 w - -,44,665,26996,391915,15628621,225254714 -r1bqkbnr/2ppp2p/1pn3p1/p4p2/P1PP4/4P3/1P3PPP/RNBQKBNR w KQkq -,32,770,24802,644780,20969518,583197256 -2r4r/1q2pk2/5n2/2p1P3/R3BPpP/3bb1P1/6K1/6NR w - -,24,1298,31534,1601708,41055255,1998497307 -2k5/8/2B2n2/8/7b/8/5N1K/8 b - -,14,248,3640,61542,965398,16079128 -8/8/k2P4/1p2n3/1p2NK1P/1P1R1R2/8/r7 w - -,25,543,13252,271258,7005277,137738438 -8/3b2r1/rpk3N1/p4pR1/PpP1Pb2/R1pB3P/3P4/1N3K2 w - -,29,780,22272,631726,17876289,526848836 -5B2/8/1n4k1/2N5/1K6/6Pp/2b5/3r4 w - -,17,545,8702,262369,4322433,126584202 -5n2/2r3kr/8/3R3p/p1p4p/4PB2/1b3K2/R1N5 b - -,29,988,28226,961060,28133623,940215349 -7R/8/1B3N2/5k2/5P2/r6p/4KR2/6b1 w - -,35,660,20605,379941,11872924,221976812 -3k4/8/2B5/2P5/2K1pN1b/8/8/8 b - -,10,219,2313,47069,535923,10526260 -4b3/2b4P/8/8/3k1r2/8/7K/4n3 b - -,35,221,7072,48020,1552093,14376329 -4n2k/5r2/5RBp/pp1p2pP/3P2p1/b5N1/R1P2KQ1/8 w - -,32,760,27172,607185,22736527,496374194 -1R6/8/2nk4/2p2K2/2PpP1nb/3P4/8/1b6 b - -,26,388,8556,117605,2533360,35089494 -1n3k2/q7/3r4/4KP1p/1b6/1R6/8/8 b - -,49,544,23774,292460,12034136,150995509 -2K5/8/k7/7P/3b4/8/b7/R7 w - -,13,253,3860,75639,1212667,24053842 -1nb2knr/6bp/p2N1q2/p1pP4/P1P3p1/R4P2/2r1PNBP/2B1K1R1 b - -,38,1315,51348,1698679,66915247,2158753800 -r2nkr2/7p/1p2p3/5Pp1/P5P1/5b1P/1R2K2R/1r6 w - -,5,186,4024,153188,3266284,124130533 -rn1k1r2/pb1pb2p/2p1p3/1NP4n/P7/1P1p2qn/R2P2KR/1QB5 w - -,1,51,968,46360,952031,43265626 -2B1k3/2b4N/1Q4P1/P2p4/3N3p/1R2p1RP/4K3/1r6 w - -,46,756,31460,513536,21349753,347937619 -r1b1kbnr/1p1p2qp/6p1/p3Pp2/2p2B2/P4N2/4KPPP/R1Q2B1R w kq -,33,923,31270,902957,31992275,953182883 -6n1/3r4/3k1p1p/1B4rP/P4P2/2BP4/2N2b1K/6R1 w - -,36,1174,35650,1076675,31889633,918863294 -2b2b1r/r1pk3p/p1n3Q1/1p2p1PP/2Pp4/PN3K2/1P2B3/R5N1 w - -,39,785,29139,614526,22128965,490042195 -8/P7/3kn3/1R5n/1p1N4/7P/B4K2/2R5 b - -,15,727,9872,434577,6086636,258205143 -1B3k2/6r1/7r/1p1ppK2/5N2/Rn4P1/1p6/1N4b1 b - -,47,1046,40904,950815,35914680,855329069 -3n4/4B1k1/PPp5/6p1/r7/N5N1/1b3K2/8 w - -,26,637,15364,386364,9157069,232911293 -rnb1k2r/pp1p1p1p/1q1P4/2pnpPp1/6P1/2N5/PP1BP2P/R2QKBNR w KQkq e6,31,949,30132,912423,29893981,897824213 -r3kb1r/1b1np1pp/p1p4n/8/2PpQB2/2N4B/PP1KPq2/R5NR w kq -,51,1779,78171,2697682,116596657,4020150684 -2k5/5n2/1p6/5rp1/1K2R1P1/2pp1b2/1R5P/6N1 b - -,27,706,18596,471003,12587719,313564418 -1n6/2N4k/7p/Pp1p3P/P2pPR1B/2R5/b4PP1/3K4 w - -,41,537,19190,260086,8901848,124436475 -8/3rk3/4n3/5P2/2p4n/2N5/3R4/2K2B2 w - -,32,767,20816,501650,12732280,309647581 -3k1B2/1B5P/8/4PbP1/1K6/8/8/8 b - -,14,375,4470,116474,1339165,34295780 -3r4/7K/7P/8/3n3k/2p5/8/5r2 w - -,2,74,247,9057,36271,1196962 -8/8/1k6/8/6pp/8/K7/3r3b b - -,30,99,2927,14920,431557,1986660 -2r3k1/7p/p4nB1/prpP2P1/P2N4/7P/3n1N2/2b1KR2 b - -,36,997,33364,915410,30365254,829612384 -4n1r1/k5p1/2b1B3/3p3p/P2P4/b4n2/KR5Q/8 w - -,41,1116,42023,1170120,42650254,1220579159 -8/n3kB2/7R/5P1K/8/1p2B3/8/8 b - -,8,239,2008,59955,571636,17128740 -6kr/3n3p/3b2b1/Bpp1n3/P1PpP3/3P4/5K2/1N1R4 w - -,24,639,13802,386183,8348822,241533544 -2k2b2/2n5/3pNq2/1r1P1bp1/pPP1PPPp/7P/p1N1K3/3R2RB w - -,39,1613,56983,2271336,75105477,2926524379 -rnb1k1nr/p1ppbpp1/1p5p/6q1/1P1p1PP1/2N1B3/P1P1P2P/2RQKBNR w Kkq -,26,1004,27067,1020256,29186007,1080313784 -2N4R/1K6/p3k3/pN6/P3n1N1/8/8/3r4 w - -,34,805,24002,513017,15000918,308130262 -2k2r2/6p1/4P3/r2P3P/1P4p1/7N/n1K5/8 b - -,30,405,11863,153995,4376351,57147838 -rn1q1bkr/1b1pp3/p7/2p2p1p/P1pP4/1P2P1p1/N1K1NPPP/R2Q1B1R w - -,33,1031,32106,1024057,32240268,1051181518 -3rkb2/4pprp/2P2np1/p7/pP3n2/1RP4b/3B1P1P/2NK1BR1 b - -,37,939,32807,882039,29760064,833163812 -6N1/K2k4/p6r/p7/P3N3/8/8/8 w - -,14,212,2921,42872,567352,8606732 -8/3bNk2/8/RP2Pr2/pb2n2P/8/2KB4/5R2 b - -,31,1074,32134,1033684,30980448,964477811 -r1b1kbnr/1p1p3p/6p1/pqp1np2/1P2PB2/P2P4/2PQ1PPP/R3KBNR b KQkq -,37,1178,44411,1454834,55227816,1853480361 -r7/2k5/Pp4n1/2pR3P/2P5/6p1/4K1B1/6N1 w - -,28,496,12834,209660,5411614,90548686 -k3b3/8/8/1N1p2p1/2n5/3p1n2/8/3K4 b - -,26,172,3843,26987,626922,4761149 -5b1r/5qk1/pp1pb1np/1P2n1pP/P2P2p1/5P2/2P1KR1N/1RQ2B2 b - -,37,962,35451,983813,35737433,1029818506 -2k5/2P3b1/4b3/1p1pPr2/1p4P1/4r3/4B3/4Kn1q w - -,3,129,780,33059,294542,12376909 -rnbqkb1r/1pppp3/p4p2/6pp/P2P2n1/3QPN2/1PP2PPP/RNB1KB1R w KQkq -,39,904,34814,861031,32884759,858341068 -r1b2kr1/p1p3pp/n2N1b2/P3P3/4P3/2P3P1/1P3Pq1/2R1K1N1 b - -,33,719,25124,525365,18988779,392663505 -4R3/1k1n4/8/1K4p1/8/2p5/3p3P/8 w - -,20,300,5454,92171,1574950,29205145 -1r5N/3bkP1p/2Bb4/p2ppr2/2pP1PpP/2p3R1/2K4B/8 b - -,37,935,29285,731805,22140748,553330594 -3n4/k5r1/3r4/p3p3/B5p1/3Kb1B1/8/3N4 w - -,6,241,4304,159667,2979995,104752017 -1rb1k1r1/p1p1p2p/1p2P2b/Qn1p1np1/1P1B1pP1/P2P1P2/1N1qN2P/3RK2R w - -,4,132,4250,138537,4409007,146128446 -3q1Q2/8/2P5/8/6k1/pK5p/8/8 w - -,26,515,11111,212340,4460917,87881066 -r1b1r3/1k4p1/6p1/pn3pR1/2QPP2P/1P6/2P1N3/4K1n1 w - -,35,863,28827,712577,23430242,597212864 -rn1k3r/1b5p/2p3q1/p1PpQ3/P5n1/2Np4/1R1P2KR/2B3n1 w - -,45,1308,46368,1430784,50316837,1621641826 -8/8/P5n1/1k5n/1p6/7P/2B1RK1R/6N1 w - -,26,398,11203,170752,4895591,74877548 -5bn1/5r2/2r1kp1p/pp5P/P2R2P1/N1p2P2/3P2BK/2B2R2 w - -,30,767,22338,558841,16449853,414126454 -4n3/7k/7p/8/3P2p1/4K3/2PQ2p1/6R1 b - -,10,258,3157,80719,1063134,28219114 -rn2kbnr/p2ppp2/bq6/1pp4p/1P3p2/P1PP4/3NPPPP/RNQ1KB1R w KQkq -,21,634,14586,444924,10977201,343829274 -8/6b1/r7/P3pb2/1nk3pp/K1P1P3/1B3N2/8 w - -,11,361,3628,108745,1192409,34321020 -6k1/8/6KP/8/8/3B1n2/8/4R3 w - -,27,247,5262,38395,896300,6467609 -rn2kbr1/pb2ppp1/2q5/2pp3p/2PP1Pn1/P1N1P3/RP2K1PP/2BQ2NR w q -,31,1109,34926,1232286,39136889,1381690119 -rnb4r/3p3k/1p3p2/pP1p3P/1P1p3N/5B2/5BK1/1RR5 b - -,18,603,11712,412870,8598229,310411215 -1B6/1r4k1/2B5/Pp6/4KN1p/8/R4b2/8 b - -,24,737,15824,503492,10755075,344787316 -r1bqkbnr/1pppp1p1/2n2p1p/p3P3/5P2/6PP/PPPP4/RNBQKBNR b KQkq -,21,623,13476,405051,9363933,289121759 -1R6/8/8/8/7n/2k5/K7/2b5 w - -,16,230,3529,53202,818143,12953522 -8/3b4/4k3/8/3p1p2/p3b1P1/6P1/2BRK3 b - -,20,201,4214,57148,1188850,18196545 -rnb1kb2/p2ppp1r/1p3npp/3p3P/5q2/P1N5/1PP1PPP1/R1BQKBNR w Qq -,29,1119,34519,1237879,41229289,1444866429 -2r5/5k1B/p4n2/prpP2P1/P2N4/7P/1b1n1N2/4KR2 w - -,30,1007,28418,901042,25127290,787734461 -8/k3b3/8/1K6/8/6p1/2B5/8 w - -,13,171,2202,28424,373650,5009878 -rnb2bnr/ppppk1p1/4p2p/5p2/P1PPP3/RP3Qq1/3K1PPP/1NB2BNR b - -,35,1133,38324,1240556,40585428,1339694293 -q2k1r2/1pN2p1p/3ppn1b/P2n2p1/P1p3BP/3P4/1BQ1P3/R3K1NR w K -,44,1338,56965,1776037,75281611,2386442073 -5k2/4PB2/7R/5P2/1p3B1K/8/8/2n5 b - -,3,104,742,24181,182046,5734998 -8/3B1n2/3p1N2/4k1n1/4p3/8/1q6/3K4 b - -,31,422,12537,170383,5002794,67527971 -r1r3n1/1p5k/1PP1p1p1/5p1p/5P1P/1R6/2K2b2/7b w - -,19,673,10908,396562,6264041,230909292 -bk3r2/b7/7p/2P4P/P3p3/2K5/7N/8 b - -,21,237,5218,57743,1327512,14733826 -r2qk1r1/1bp1p2p/1p2Bbp1/p1P1P3/P3NB2/1P3P1P/2K3P1/RN2Q2R w - -,53,1624,73859,2233879,99276190,3014460354 -rnbqkb1r/pppppppp/7n/8/P2P4/8/1PP1PPPP/RNBQKBNR b KQkq -,20,579,12934,390277,9653490,303024872 -8/p6k/P4n2/qp1p2Q1/3P3p/7P/6R1/B1N3K1 b - -,20,644,10737,352607,6304345,205910674 -1rbq2n1/p1pp2p1/P2bp3/1p3rk1/P1P3Pp/B6P/R2P2RN/1NQ1K3 w - -,27,959,26429,914458,27040297,924159048 -1N2R3/8/3p1P1k/p6P/2nK4/7r/7p/3b3n b - -,29,502,13377,225641,6078932,102713881 -6k1/2n2Rbr/1p1p2Bp/Pp4pP/3P2p1/1R2K3/2P3Q1/5N2 b - -,16,696,10229,440228,6624911,279444500 -8/6N1/1p6/8/5k2/8/2K5/8 w - -,12,91,1032,7624,86951,624933 -3r1qr1/p4k1p/1B2pnp1/2p5/P1b1Pp1P/1P3P1B/1R1P4/2BK1R2 b - -,40,921,34193,832045,30492843,778609057 -5n1k/8/2B3p1/4p1bp/7P/8/6K1/4r3 w - -,15,380,4844,122187,1461763,37238114 -2r5/5b2/p3Pn2/P1kP1B2/2p4p/7N/6P1/2KN2R1 b - -,28,713,18704,493391,12311178,333404687 -1r1k1q2/6r1/p3pnp1/2p2B1p/P3PB1P/1P3P2/R2Pb3/2BKR3 w - -,3,120,3713,139808,4336135,160613981 -8/K3Nk2/p7/p3r3/P7/8/1N6/8 w - -,14,256,3449,59501,826611,14162977 -1r4k1/p7/PRP5/2P4r/B7/4q1P1/1P3K2/8 w - -,3,119,1621,57008,864830,30161914 -2k5/4Bb2/p7/P7/1r6/3p4/8/QRK5 b - -,28,621,13681,357782,7209904,206725595 -b7/5K2/8/2r4k/8/2p3b1/1n6/2r4n w - -,7,297,1402,60085,267108,11657971 -1rb1kbnr/pp1ppp1p/nqp3p1/4P3/3P1PP1/P4N2/1PPQ3P/RNB1KB1R b KQk -,27,961,27749,975626,29296348,1036229498 -b2b4/5r2/4K2k/8/8/2p5/1n6/2r4n b - -,46,128,5334,17931,752841,2495195 -N2q2nr/1p2b1k1/8/5Ppp/pp2B1P1/B1P2N1P/P2pK3/R6R b - -,37,1398,51304,1790842,66030351,2200899685 -1r6/8/1k4p1/7p/P4P1P/2B5/3pR2R/7K b - -,19,475,9298,238282,4714126,125520872 -3rnb2/4p2p/3k4/p4n2/2p3rP/2ppp2K/PB1N4/RN1Q1B2 w - -,25,902,23114,796141,21813797,738664733 -6nr/p1k5/2bN4/2P1p3/2PPqp1p/4RPPB/QK2R3/8 b - -,31,1223,37493,1475983,46876636,1855588834 -1nb4k/3pp1r1/5pp1/1Pp1b2p/5PPP/BpqPPN2/2R1K1B1/1N5R b - -,32,1057,34732,1160792,38694621,1293807512 -r1qk1bn1/pp5r/B4p1p/1Pp1p2Q/P1P4P/2RPBb2/8/1N2K1NR b - -,35,1238,41225,1495619,48989015,1814335108 -2b2r1k/1r1p4/2P5/p1N2p2/P4PPp/1P5P/NQ1K1n2/1R4n1 b - -,3,106,2631,85781,2232951,73152280 -B3n3/6b1/3kr1pp/P3p3/4n1P1/2PPP2P/R2Nb3/B3K3 w - -,22,494,11765,281677,6961428,175251672 -B7/6k1/1P4P1/pR3r2/8/2K5/8/8 w - -,24,455,10263,179513,4112681,68800228 -1r3b2/1Bn5/p2p1k2/P1p2p1Q/3P1p2/P2K2p1/b2B3R/R5N1 b - -,29,1267,32124,1371751,34991783,1464750728 -5b2/r1B5/nP4k1/pP3b2/2P1P1p1/1N4P1/1R3KBP/4r2R w - -,31,1068,32299,1105756,34548813,1170898741 -r2k1br1/2p1pp2/2nqb1p1/pp6/QPPp1n2/B2PPP1P/P2N2B1/1R2K1NR b - -,40,1081,44360,1220750,50480880,1435045815 -1nbq1r1k/2ppn2p/rp1P2p1/P5BP/3N1p2/1Q3R2/P3PPP1/R2K1BN1 b - -,23,1138,27614,1351108,35206290,1704158842 -8/8/p1Knk3/pN5r/P7/8/8/3N4 b - -,27,319,7036,88268,1971497,26014246 -3r4/1p2pk1p/3p3n/5Pp1/2P1R1b1/2b3P1/3K1N1P/B4B1R w - -,6,198,5420,163091,4688227,137519993 -3n4/8/K7/5k2/8/8/8/8 b - -,12,49,617,3568,44621,243880 -r1bqkbnr/p2pp3/2n2p1p/1pp3p1/P1P1P3/NP4P1/R2PNP1P/2BQKB1R w Kkq -,27,696,20141,549910,16767170,482022499 -6k1/8/1p6/8/1n6/3b4/7n/4K3 b - -,25,77,1873,8261,197864,844458 -6nr/pk1q3r/n6Q/P1bp3p/Rp1PPP1P/1P4PR/4N3/1N3K2 b - -,34,1040,31516,969539,30113720,934813851 -rnbqk1nr/1ppp4/4p1p1/pPb2p1p/3PP3/5P2/P1P2KPP/RNBQ1BNR b kq -,34,1142,38630,1279346,43362539,1431196358 -b7/1k6/4r3/1B1p4/P2P2pp/2Q3n1/1K6/8 w - -,33,703,20946,416404,11859396,231724667 -4kb2/1b2pr1p/PBp2np1/3PP3/1rP5/1N4PB/p3KP1P/3R3R w - -,48,1281,56030,1619841,64891411,1980801129 -r2k1bnr/pp2qp2/B6p/1Pp1p1pQ/P3p1bP/R1PP4/3K4/1NB3NR b - -,32,775,24702,696377,22350477,685368052 -7r/8/8/1pk5/8/4n1p1/8/K7 w - -,3,93,469,13558,54668,1517205 -4k3/7N/P5P1/3p4/2Q3B1/4pNpP/4K3/1R2r3 w - -,4,29,1268,10103,426748,4278244 -r7/n4b1r/3P1k2/pP3pp1/P2R1PPQ/b3P3/8/4KR2 b - -,34,941,30157,873463,28524390,854084161 -3k1b2/rp3pr1/1n4pp/pPpp1P1R/2NP1p2/P1N5/1BP1P3/1R2KB2 b - -,24,774,18349,595724,14297090,466876722 -3R4/2k5/1R6/p3b3/4B2p/3K4/2r2P2/6r1 w - -,39,1334,43130,1344878,41510060,1236784558 -2K1b3/2R5/P7/8/8/8/8/5k2 w - -,17,176,2915,33729,576894,6926473 -B7/5r2/p3N1k1/PP1Rb2p/8/8/3K3B/8 b - -,33,958,24375,742801,17140962,538574788 -qbn4r/1bN4k/8/p2P1N2/2PBp2p/3BPP2/P3K1p1/4RR2 b - -,29,967,29633,1017435,32558313,1132799477 -r1bqkbnr/pppppppp/2n5/8/3P1B2/8/PPP1PPPP/RN1QKBNR b KQkq -,22,698,16762,532558,13830060,447815701 -5B1r/2k4p/4p2P/R5p1/1r2BP1P/2Np3K/8/2B1R3 w - -,54,1162,58071,1233007,59195193,1281733892 -8/prbpkNr1/b6p/3pB1pP/2B2P2/P1n3R1/Q1P3P1/1R2K1N1 w - -,46,1489,65825,2057058,89173702,2743182051 -r1bqk2r/1p1p1pbp/4p3/p1p1nPp1/2PP4/5P1N/PP1K2BP/RNBQ2R1 w kq -,31,983,30614,981359,32127091,1039623969 -1r6/2n1k2b/2B4p/4B3/6K1/3p4/4p3/R2R4 b - -,38,1434,47629,1736488,55292550,1956984792 -5k2/6R1/1p2B2N/1P6/P7/4K3/7b/b4r2 w - -,34,862,21899,559270,13808283,355117260 -rn1qk2r/p2bp1bp/1pp2p2/3p1np1/2B2P2/N1PPP1PP/PP6/R1BQK1NR w KQkq -,31,891,28171,846924,27110463,842343015 -3k4/8/2B5/2PN4/2K1pb2/8/8/8 w - -,19,250,4795,54526,1028885,11864066 -q1r5/p3n1p1/P1bpR3/1pP2P1k/1B1P3p/2Q4P/1R3N2/5K2 b - -,26,1013,26582,1051947,28292399,1129941859 -2k5/K2R4/2N5/8/4r2P/5p2/8/2b5 b - -,23,484,9078,178874,3456982,66261750 -5Bq1/k4r2/4p1p1/p2n3p/P1p4P/2rR1PK1/7R/5B2 w - -,29,999,26983,924685,24803506,857412710 -1k6/1bN5/3B4/8/8/6r1/4p3/b3K3 w - -,17,364,5917,154705,2444920,68614890 -6r1/3k2N1/2n5/3pbP2/8/8/8/3K1n2 b - -,37,280,10072,87498,2933513,27066592 -8/2p5/rp4P1/1pk2pNp/5P2/8/2n1bK2/1N6 b - -,28,399,9565,140045,3382179,50230671 -rnb1qbnr/2pkpp2/p2p2Qp/1pP5/2N5/4P3/PP1P1PPP/R1B1KBNR b KQ -,21,915,18268,750848,16451990,654431165 -1rbqkb1r/1p1p2pp/p1p2n2/1B2pp2/3P3P/1PP1P1Q1/P2K1PP1/RNB3NR w k -,39,1171,43744,1338114,49376506,1532521673 -3r4/1k6/pb4P1/PppR1p2/8/R1r1B2b/1P1QK3/8 w - -,36,1109,38177,1132976,39971118,1166413111 -2b1rb2/3k1r2/Q1n2ppp/2P1pP1P/2p1p2B/NR3N2/P2P4/1R3K2 w - -,47,1152,54049,1267239,58480874,1380169093 -3b2n1/1k6/4b3/2pPbPp1/3R2Pp/p3KN1P/8/1B1N2R1 w - -,34,1085,33909,1007127,31133588,891220430 -8/k5b1/2B1P3/8/8/1Q3p2/K5P1/8 w - -,32,329,10469,116555,3760636,44739152 -5bkr/3P4/4r1p1/p2Qp2p/2p2P1P/P3P3/3B1K1R/R2N1BN1 b - -,17,848,15877,768267,15989434,762435906 -6n1/6k1/3P4/5P2/p1R1N1p1/P2K4/r2N4/4b3 b - -,18,418,7787,187467,3742631,90489155 -6nr/1k1r4/2n5/Pp1p2Pp/1p1PP2P/1P3N2/8/RqN1K2R w - -,21,685,14039,468200,9747865,332529286 -2b5/6r1/rpk5/p3bpR1/PpPpPN2/RQ1B3P/3PK3/1N5q b - -,39,894,33679,831921,30816591,806592354 -8/8/8/3N4/5Pkp/BR4p1/3R2K1/3r4 w - -,35,372,9773,124778,3556234,47377424 -8/4k2N/2Bp1b1R/3q1n2/4p3/8/7n/4K3 b - -,37,594,21167,366328,12692907,230801830 -8/2k5/8/2P5/B3pN1b/2K5/8/8 w - -,23,267,5178,60640,1146671,13926198 -1k4r1/7P/p2n4/P1p4R/1P6/1P5P/1N3Kb1/1rB1rB2 b - -,47,1413,59268,1760858,70553639,2099816683 -3k4/r5b1/2P4r/1pqppb2/Bp1P2n1/2N5/6PR/5KB1 w - -,24,1217,28126,1367656,32157613,1517592407 -4k3/K3N3/p7/p3r3/P7/8/1N6/8 b - -,17,218,3645,47612,775095,10479185 -1r1R4/7k/3Q3b/3NP2p/Pp2P2P/5N2/5K2/8 b - -,15,606,7797,317799,4425599,178438891 -k5b1/2K5/5R2/8/8/b7/7P/8 w - -,21,281,5141,79437,1389055,22793609 -rnbqkbnr/1pppp1p1/p6p/5p2/7P/7N/PPPPPPP1/RNBQKBR1 w Qkq -,20,358,8094,165912,4158765,95810744 -3qkb1r/2p1pp2/r1n1b1p1/pp5n/1PPp4/B2PPP1P/P2N2BR/1R1QK1N1 b k -,37,1039,39368,1138903,44123893,1316111751 -8/8/1k6/1p6/8/K3n1p1/4r3/8 b - -,25,51,1287,4210,107892,389618 -r7/1kb4Q/p2B2P1/PppR1p2/5r2/RP5b/8/4K3 w - -,32,851,26842,704787,23609109,624968709 -1n6/b4k2/p2p4/P2P4/P1p2B1Q/2N2K2/4B3/7R b - -,13,579,7564,333171,4461640,194329314 -1k6/4N1q1/6P1/2b4n/8/7N/8/7K b - -,31,327,10093,114605,3696030,44223299 -4R3/6p1/5n2/4K1k1/8/8/8/2qb4 w - -,12,422,4815,171119,2026540,71528492 -b5nr/3p4/2n3pb/p1p3k1/2p2r2/P4P2/2K1P1BP/7R b - -,30,576,17054,321085,9772523,182349904 -2k5/8/5N1n/8/8/8/3NK3/8 b - -,8,165,1609,29733,301314,5328628 -q1b2bnr/r6k/p1PN4/3Pppp1/2P4P/N3PPP1/PB1KB3/R5R1 b - -,27,1133,31884,1251285,37118589,1403131893 -8/8/r6b/P3pb2/1nk3pp/K1P1P1N1/8/B7 w - -,11,361,3590,108753,1152635,33862240 -2r4B/p1p3p1/2r1P1k1/P5P1/nR6/1P1N2N1/1b1K4/8 w - -,32,865,24190,682484,18683538,540011176 -b3k3/n7/P7/2p5/2PpP3/3P2KN/1p5n/2b5 b - -,24,212,5499,50877,1378616,13212407 -3k4/8/6Q1/1P1P4/2nP3P/8/4K3/1N6 b - -,12,411,3651,109944,944441,26742776 -5n1k/1B6/3b2p1/4p2p/7P/8/7K/8 w - -,14,194,2542,38699,504138,8103597 -rnb1k1n1/p6R/1qppp3/Pp2Pp2/1P4p1/3PN3/2PRN1P1/2K1bBQ1 w q -,37,1028,35077,962993,32371038,888668768 -1r4N1/P2r3n/2p1k2p/P2p3P/3Pp3/1P2Kb1R/1BB2R2/8 w - -,34,1031,34281,946021,31990350,849913429 -k4Nnr/1n6/4K3/1p1P2Pp/1p1P3P/rP3q2/8/6RR b - -,38,486,17901,284660,10422692,184989760 -8/5n2/8/8/6k1/K7/8/8 w - -,5,70,470,5992,37383,465839 -1rbq1bn1/ppppp1p1/4k1r1/P4P1p/P7/B1P2N1P/3P1PP1/RN1QKBR1 b Q -,4,125,2808,88980,2042403,67081431 -1b3k2/7B/1P6/p5P1/P3R3/8/1K3p2/8 w - -,26,330,8038,121936,2841823,48470286 -4k1n1/N7/3P4/5P2/p1R2bp1/P2K2N1/8/5r2 w - -,27,578,13677,308860,7098019,162077682 -rnbqkbnr/pp1p3p/6p1/2p1ppB1/2N5/P2P4/1PP1PPPP/R2QKBNR b KQkq -,26,910,24012,816801,22637052,762051290 -1n1K4/3b4/8/1kp5/3q4/8/1B6/8 w - -,7,243,1821,59735,542116,17828496 -2r3k1/2q1n1B1/1p2p3/pp1N1p2/P4Pp1/2Q4b/5K2/6N1 b - -,29,1069,32425,1081428,33752136,1072228595 -b1r3nr/n2p4/4k1pb/ppp2Rp1/2P2N1P/P3KP2/4P2P/5B1R b - -,4,72,1789,39462,1025826,23595425 -4kb2/1b1npr1p/PBp3p1/3PP3/1rP5/1N1R2P1/p3KP1P/7R b - -,31,1228,39919,1479331,49654895,1753184604 -1r2k1n1/p2pq1p1/1p4N1/2r2p2/2b2PPp/b1p5/P3P2P/RQ1KBB1R w - -,29,1316,35746,1563050,44760160,1913302282 -1n1qk3/8/2rPK3/5PNp/1PR2q2/8/R7/4b3 b - -,43,941,39779,845793,35534131,747325408 -8/1k6/1P3B1p/5p1r/7R/b2P4/4N1K1/8 w - -,36,587,17272,293471,7842204,139751842 -1n2kr2/N1bb3p/pp6/1B1ppn2/3p1p1q/PPP1PK1P/3B4/3R2NR b - -,38,890,33400,780525,29869454,713992175 -rnbqkbnr/p1pppppp/1p6/8/P7/7N/1PPPPPPP/RNBQKB1R b KQkq -,21,441,10183,239574,6046659,156453781 -rnbqkbn1/p2ppppr/8/1pp4p/7P/3PQ1P1/PPP1PP2/RNB1KBNR b KQq -,23,731,18399,634916,17336311,624993363 -6k1/n2BR3/7P/5K2/8/8/8/8 w - -,25,125,3111,18474,438628,3056100 -1n1qk2r/r2b2np/pp1bp3/1Npp1p2/2B2pP1/PPPPP2P/3B1QK1/R5NR w k -,34,1091,37321,1238914,43057396,1464655404 -rn1q1bn1/p2p1kp1/1pp1p3/5p2/P1b5/R4R1B/1P1PPP2/1NBQK1N1 b - -,37,1021,35760,995227,34195024,997267525 -1kn1R3/5b1P/pr3B2/P1p5/1P5P/1P3B2/1N2K2r/5r2 w - -,4,137,4790,161531,5392456,185702712 -1r3b1R/1Bn5/p2p1k2/P1p2p2/3P1p2/Pb1K2p1/3B3q/R2Q2N1 w - -,43,1820,68989,2737518,102602845,3898597088 -4k3/r7/p2P2B1/p1p3n1/P7/N6P/1b6/1n2KR1N b - -,4,106,2527,63219,1547722,39821027 -8/8/5k2/p1q5/PP1rp1P1/3P1N1B/2RKp2r/6N1 b - -,42,763,28895,566531,21004779,433156046 -3k2n1/r4b2/p2p4/P3P3/1Rp1P2p/2K4N/B3Q1P1/3N2R1 w - -,41,798,32913,658945,27207402,558905055 -8/8/K7/1P6/8/2N5/6k1/8 b - -,8,96,516,5915,36004,417299 -1n6/Bb3r1k/1P4p1/4p3/2pp1PpP/4Pp2/8/1n2R1RK w - -,16,501,9071,276548,5502277,164496944 -8/6k1/8/2q3N1/Pp1rp3/2RP1N2/4K3/1r6 b - -,42,900,35044,740651,28133646,589858814 -1n3k2/7p/2bn4/2p5/P1PpP1KN/1pBP4/7b/4R3 b - -,31,740,21119,502412,14158043,334357897 -8/K6k/1n6/1P6/8/6N1/8/8 w - -,10,101,996,9748,101893,1039621 -r1bqkb2/3ppprp/p1p3pn/1p2n3/2PP2Q1/NP6/P3PPPP/R1B1KBNR w KQq -,38,883,29263,751949,25272235,697446109 -6B1/r5k1/8/6bn/2np3r/2p2b2/3R4/4K3 w - -,17,911,15124,759261,13034930,628641498 -8/6kN/P3B1P1/3p4/8/2R4P/4p3/2K1N1b1 b - -,11,325,3782,108961,1350152,38636686 -rnbqk2r/pp1pppbp/3P4/2pn1Pp1/8/8/PPPBP1PP/RN1QKBNR w KQkq -,27,939,26525,884800,26250686,854384776 -8/8/np6/2p5/1pk1NP2/5K2/8/8 w - -,15,128,1843,17389,236542,2455407 -4q3/8/k1B1P3/8/1R4p1/KQ6/6P1/4b3 b - -,23,800,16611,579238,12534867,435842164 -rQb2kn1/1p1pq2r/p7/1N3pNp/P3p3/2bPPP2/1PPB2PP/1R1K1B1R b - -,40,1663,59190,2405059,83607989,3348495751 -2k4b/2P5/2Q3p1/4p1rp/2RN3P/1R4B1/8/3Kn3 b - -,11,550,6892,319284,4628663,206187921 -3r4/b3k2n/8/1P4P1/2P4N/p6r/5RK1/8 b - -,37,714,21368,376906,11231938,202698399 -b2n4/6b1/P1pBkP2/8/2P3P1/p5p1/N2RK3/1N6 b - -,12,373,5072,158068,2410089,74130034 -5k1b/8/3R4/8/3p4/B5p1/1Kb3P1/8 w - -,17,135,2535,28522,564876,7612156 -rn3k2/p6p/2p5/4Bp2/6PP/8/5P2/KR2b3 b - -,18,496,8766,227105,4271881,107203047 -r4q1r/pb1k2bp/P1p2B2/3pp3/1PBPP3/5NP1/1P1NKn1P/7R w - -,38,1373,50094,1783230,62608240,2220029765 -3R4/1N6/3p1P1k/4r3/6n1/2K5/7p/3b3n b - -,29,510,14123,257021,7179553,134871038 -3k4/8/8/4n3/8/3pN3/8/1K3N1r b - -,22,253,5783,73453,1698540,22296706 -1k4n1/b7/5P2/8/3p2Pp/5RbP/b3KN2/1B6 b - -,22,519,12057,281430,6789205,160564570 -1n3B1r/5b1k/1p3p1P/1P1p1NR1/1p1p4/5B2/6K1/4r3 b - -,27,712,17684,470872,11605852,309923373 -5N2/5k2/Br2n3/8/P2P4/KPp2P1p/7P/4Q2R w - -,34,728,24293,483749,16186142,310259546 -8/5Bk1/3BP2R/5P1K/1p6/3n4/8/8 w - -,22,160,3217,23407,516653,3824396 -6nr/2pbp2B/Br5k/4P3/1b4pP/q5P1/5P1K/3R2NR b - -,43,1324,55899,1651559,70120828,2049603592 -r1bB1qr1/p3bk1p/np2p1pn/2p2p2/6P1/PP2PP2/1R1PQ2P/2B1KBNR w K -,28,717,20873,582873,17964538,536721710 -1b6/8/1k2P3/8/2Q3B1/1K6/6P1/8 b - -,10,322,2980,98469,1042978,34026733 -rnb1kb1r/1p1ppppp/1q3n2/p1p5/P1P2P2/8/1P1PP1PP/RNBQKBNR b kq -,30,596,18357,418219,13249032,331238921 -3n4/5b2/4p1k1/4P2p/Qp2P2P/5B2/4K3/2N5 b - -,8,230,2371,67132,745469,21123065 -r4b2/2pkp1r1/2n1b1p1/pPq2p2/p1Pp1P2/B2P1P1P/P2N1KB1/5RNR w - -,20,609,13513,401365,9417723,283487112 -8/1K5k/8/8/1P4N1/6r1/3n3N/8 w - -,16,313,4791,96787,1472122,30284816 -1n1r2k1/3b2br/1p1R3p/p1P5/7p/4Pp2/5K2/1N4RB w - -,33,763,23826,624577,18765475,534384036 -1n1r4/2R5/5npb/2pp2k1/P1p1b2r/2K2P2/6BP/8 w - -,19,575,10383,312853,5550712,170003279 -N4b2/2B4r/3q1P1k/8/PpP3P1/1B6/8/nK3R2 b - -,31,797,23519,600349,18111309,461028678 -2K5/8/8/1k5P/3b4/8/b7/R7 b - -,28,390,8864,142793,3058230,50423585 -2b3k1/r1nN4/1P1P4/1P2b1p1/p4p2/P2Kn1P1/3N2Br/7R b - -,44,1517,62070,2019427,81164552,2558638757 -r1bqkbnr/ppp2ppp/2n5/3pp3/1P2P3/5P2/P1PP2PP/RNBQKBNR w KQkq -,27,1021,27435,1032315,28540029,1079828764 -bn2nbr1/2q1p1p1/1Bk3B1/3pP2p/P2P4/2r2P2/2R3p1/Q3K1R1 b - -,22,756,18536,634539,17356165,589652660 -2kNN3/r7/8/1P1P2pP/8/2n1r1p1/2K5/8 b - -,36,519,16477,237605,7169511,103601526 -4k3/7p/2b4P/3p4/p1p2R2/1Bb3p1/4K3/7r b - -,35,638,18904,327939,9421469,162356881 -3k4/3r4/2n3n1/5P2/2p3B1/2N2b2/1K6/3R4 w - -,31,929,25012,753183,18964053,563262424 -2r1r3/8/2k5/8/2K3p1/8/8/8 b - -,21,99,2695,13249,384507,1870145 -qB3b1r/1b2n2k/p7/3PpNp1/2P4P/N2KPPp1/P3B3/B3R1R1 w - -,37,788,28609,695804,25326210,679876259 -rn3b1r/pBp1pk1p/4bp1n/1p4p1/8/N3Q3/PP1P1PPP/R1B2KNR w - -,44,1181,47975,1261222,49848182,1310873122 -2b5/8/4nr1k/P2p1p2/1p3PPp/1P2R2P/3K1n2/8 b - -,25,409,10320,161585,4154571,63519762 -7r/pk1n1p2/1pp1p2b/8/1P4K1/1Bn5/Pr1N4/4R2R w - -,37,1650,54298,2348712,74980156,3161481181 -rn2k3/pb6/P1ppp3/1pqPP3/1P4p1/2P5/3RBbPQ/2K5 w q -,34,824,26397,661699,20615727,531670633 -1n2kb1r/1q1bp1p1/rp1p2p1/p1p3NP/P1PP1pn1/1P2PNPB/5P2/R1BK3R b k -,36,1179,42039,1405190,49477113,1678276093 -k7/P7/1p4r1/3R4/2P1B3/5Np1/8/2K5 b - -,13,439,4180,136456,1622478,50844728 -1r2kqr1/2B5/p3pnp1/2p2B1p/P3Pp1P/1P3P2/1RKP4/2B1Rb2 w - -,25,815,20282,671389,17141895,578200930 -1r3bn1/5k1r/5p1p/pp1p3P/P5P1/2p2P2/1R1P2B1/1NB2RK1 b - -,26,521,13533,304058,7899917,191759894 -6n1/2k1N3/6P1/b7/8/p5K1/7N/8 b - -,15,220,3634,53299,939606,13995250 -r1bq1bnr/pppk1ppp/2np4/4p3/3PPB2/6P1/PPP1KP1P/RN1Q1BNR b - -,31,1016,30780,1036367,31838047,1085683121 -b7/b1Pkr3/7N/7P/P3p3/K7/8/8 b - -,23,282,5982,86936,1926183,29692100 -4k1n1/N3b3/3P4/5P2/p1R3p1/P2K4/4N3/5r2 b - -,24,670,14872,379813,8397646,205324209 -8/nbk5/P7/2p5/2PpPKnb/3P4/1p6/8 b - -,33,162,4897,28508,785349,5339815 -r1b2r2/1p1p2k1/nb1q4/p3p1p1/PBp4p/4npPK/1QP4P/RN4NR b - -,53,1229,59419,1447371,67473824,1739274850 -7n/1B6/3p4/4k1n1/4N3/3K4/8/2q5 b - -,31,360,10512,138766,3884338,54133768 -8/7p/8/7k/1N3P2/BR1R2p1/7r/B5K1 b - -,16,425,5930,174064,2404582,76277431 -7K/1r6/2nr3P/8/7k/2p5/8/8 b - -,39,88,3294,8832,320536,1512911 -4n3/7k/7p/8/3P2p1/4K1p1/2PQ4/6R1 w - -,27,262,7282,78757,2207853,24641537 -rnbqkbnr/ppppppp1/8/7p/8/3P4/PPPQPPPP/RNB1KBNR b KQkq -,21,586,13754,419311,10730679,348067988 -5rk1/8/3r4/1p6/3NQ3/Ppb3KB/6n1/8 w - -,40,1344,46282,1530710,50155607,1640991711 -8/6p1/1R6/7q/2K3n1/6k1/8/3b4 b - -,37,574,19230,272283,9057166,127759961 -1B3k2/6r1/7r/1p1ppK2/4n3/R5P1/1p4N1/1N4b1 w - -,24,1085,22792,941251,20505827,809275923 -8/8/3rk3/2K5/5P1p/pR4b1/8/8 w - -,17,311,4452,92027,1387296,29987218 -r2k1br1/2p1p3/2nqb1p1/pP3p2/p1Pp1n2/B2PPP1P/P2N2B1/1R2K1NR w - -,27,912,22937,803846,20351194,729814225 -rn1q1bnr/3kppp1/2pp3p/pp6/1P2b3/2PQ1N1P/P2PPPB1/RNB1K2R w KQ -,30,856,26922,784949,25488551,760364787 -2b1k3/r1np3r/1P1P2p1/5p2/pP3Bn1/3K1NP1/P7/bN3B1R w - -,37,1378,45097,1587268,50942868,1734435797 -1r6/2k5/8/2PP1R2/4p3/1K3Pp1/6p1/8 w - -,6,144,1997,38907,577253,11245312 -8/1k6/8/8/5b2/3K2p1/1r6/5B2 w - -,7,180,1853,46463,517961,12738707 -8/1q6/2P2P2/7k/p6p/8/8/1K6 w - -,5,102,565,11829,81776,1823049 -q7/p1rbn1p1/P1ppR3/1PP2P1k/1B1PN2p/1Q5P/1R2K3/8 b - -,23,1082,22483,1018531,21880365,963053137 -8/8/1kq5/1pN5/1p1p4/5B2/8/3K1n2 b - -,25,459,11626,193250,5047908,80460506 -1n1r4/3R4/5npb/2pp1k2/P1p1b2r/2K2P1P/6B1/8 b - -,36,524,16408,246547,7849552,121631710 -q1b2bnr/r3p2k/p2N4/2PP1pp1/2P4P/N3P1P1/PB1KBP2/R5R1 w - -,48,1087,47239,1188227,49151658,1338567142 -1n3r1k/2qpP2p/B5p1/Pp1b2BP/3pPp2/5R2/P4PP1/R3K1N1 w - -,40,1456,53761,1817163,67078205,2194309424 -rn3b1r/p1p1p2p/B1k4n/1p3pp1/8/8/PPNPKPPP/R1B3NR b - -,17,485,8989,249909,5205688,144165616 -2k5/K2R4/2N5/8/7P/5p2/1b5r/8 b - -,19,422,7325,149623,2766533,54402120 -r1bqk1nr/p2p3p/np5b/Q1pPppp1/6P1/P7/1PP1PP1P/RNB1KBNR b KQkq -,22,735,17486,584660,14818830,498543274 -1kn3r1/7P/p7/P1p4R/1P6/1P5P/1N2BKb1/1rB3r1 w - -,37,1240,41774,1444864,47319697,1650588070 -6n1/N4R2/3kP3/P7/6P1/7p/4b3/1K6 b - -,16,348,5468,114917,1857899,38841885 -6br/8/2B2k1p/r1pp4/3P1K2/1P2pn2/4R3/4B2R w - -,35,922,31463,846637,27998300,775606063 -2k1q1B1/4b3/8/7n/8/8/5N1K/8 b - -,27,428,13236,200078,6556289,99020773 -rn3b1r/p3p2p/B1pk3n/5pN1/8/8/PPpP1PPP/R1B1K2R w - -,30,473,13724,245920,6991944,142885527 -8/6Q1/p2bk2p/P7/5R2/8/4b3/2R3K1 b - -,19,905,13909,598054,9126433,374198681 -1N6/8/3k4/4R1K1/3nP3/8/4Q3/8 w - -,36,317,9428,77484,2566598,20508600 -kn6/4N3/8/2P5/2B5/1p6/8/1K6 b - -,6,120,898,16730,139234,2494469 -1r6/3r1bk1/2B4p/P1pp2n1/3PpK2/1P6/6RR/B7 b - -,33,1011,30180,921206,27258414,824303656 -q7/1r6/5P1k/4b3/1pPR2P1/3Kn3/8/1B6 b - -,44,620,24932,407315,15620313,278021386 -1b6/5b2/rp4r1/p1k1Pp2/PpP5/2RB2RP/3P4/1N2K3 w - -,23,610,15191,398930,10339869,272689854 -3r4/p1p3p1/n3P1kp/P1r1P1P1/3b2q1/1P1b1PN1/4N3/2RK4 b - -,50,1019,48239,982370,45731875,935933031 -3r4/p1p3p1/n3P1kp/Pr4P1/3bP1q1/1P1b1PN1/3KN3/2R5 w - -,30,1572,40938,2029965,49416145,2362203518 -4Nk2/7b/4R3/1B4P1/1P5R/p5B1/8/4K3 w - -,48,437,20166,211042,9320900,103192606 -1n1qkb1r/1bp2ppp/r7/pp1pp2n/2PP1B2/1P3P1P/P3P1P1/RNQ1KBNR b KQk -,46,1442,63634,1978598,84879594,2638284448 -8/7p/2k4P/5q2/1r6/8/8/4b2K b - -,51,124,5991,18322,860208,2337387 -r1b1kb1r/pp1ppppp/n1p4n/6Q1/3PPP2/4B3/P1P1K1PP/RN2qBNR w q -,3,86,2847,82223,2693821,80040481 -1rb1kbr1/pP1p3n/1q2p3/6p1/P2P2Pp/2p4P/2P1P1B1/RNBQK1NR b K -,36,1076,35825,1081636,36143694,1116052443 -4qbn1/r3k3/B4np1/1p3p1r/p1ppPP1P/P1P1Q3/1P1Bb3/RN2K2R w KQ -,24,920,24030,942258,25977085,1034545119 -Q1n1k3/2rbp3/N3P1r1/p6P/6p1/5P2/4K2P/3R3n w - -,36,828,24723,595207,18206229,461619963 -2rb1r2/4k3/B5p1/pQ2p2p/P3PP1P/8/3p1K1R/2RN2N1 b - -,28,1115,26347,1027677,24693798,950653925 -1rbk1b1N/pR4rp/2pp4/2n1pp1p/1p1PPP1P/6PR/2P1B3/1K2B3 w - -,39,1234,43921,1351782,45507295,1385853506 -8/8/6k1/1n1P2np/6p1/Q2K4/1RP5/8 w - -,26,472,13487,232887,6794619,112696263 -5R2/4k3/2r5/B4P2/8/7p/N7/3R1K2 w - -,35,468,15336,196787,6234860,83780388 -2b4r/1r1kb2p/p1Q5/npp1p1PP/2Pp4/PN3K2/RP2B3/6N1 b - -,3,74,1789,44044,1137828,29655138 -8/2k5/4p3/4P2p/4P2P/1K3N2/2B5/8 b - -,7,112,667,10558,58224,933223 -4k2b/1B5N/p2p4/P3p1P1/1Qr4p/N1P4P/6K1/1R5R w - -,40,636,25703,400987,16689636,259663000 -r2n3r/1bNk2pp/6P1/pP3p2/3pPq1P/1P1PB2R/2P3p1/Q3bKN1 w - -,3,129,4008,165481,5247775,214019551 -rnbqkbnr/pppppp1p/6p1/8/7P/3P4/PPP1PPP1/RNBQKBNR b KQkq -,21,586,13622,388092,9897664,289611652 -r3q2r/pb1k2bp/P1pp1p1n/4p1B1/2pPP3/6P1/1PP1BP1P/nN1K2NR b - -,35,1106,37358,1139126,38282191,1144648232 -k7/8/p1b5/4r3/8/8/5K2/8 w - -,3,84,333,8658,35221,892702 -r5n1/p2bk3/q2pn2P/2p1pp1p/pPPN1pP1/Q2P3R/2K1PP2/2R2B2 w - -,38,1361,49022,1748549,63042782,2252383887 -8/8/1r3P1k/1rp2P2/4R2P/1b4P1/7p/R6K w - -,31,652,17565,410826,10382438,263637624 -rn3bnr/p7/3ppk1p/1b1P1pp1/pP2P3/R7/3pNPPP/1NK1B2R w - -,6,182,5932,176385,5433647,162977844 -r4qnr/p1p1kpp1/2n4p/bp1p2P1/3P3P/1B2P2b/PPPQ1P1R/R1BNK3 w Q -,22,798,18719,674094,17011653,612906090 -2k3r1/3n4/1p3p1b/pPN1p3/B7/2R4K/P7/2R5 w - -,29,617,18389,377811,11135333,236493330 -5rk1/p7/P1P5/2P2r2/1R4K1/3B2P1/1P6/8 w - -,22,449,9375,199401,4233692,92012031 -1n2kbr1/1bB2p1p/r5p1/1p5n/pPpP3q/5P1P/P3P1P1/RNQK1BNR w - -,32,1462,43775,1944381,58018191,2521903790 -1rBk1bnN/q7/1p1p4/B2Pp1p1/2b1np1p/5PP1/2R3R1/4K3 w - -,31,1200,36420,1359242,41213148,1517398285 -8/4kb2/4p3/4PB1p/4P2P/2K5/1p6/6N1 b - -,12,167,2360,30911,485142,6240922 -1n3R1k/3p3p/B1q3p1/Pp1b2BP/3pPp2/5R2/P4PP1/R4KN1 b - -,2,84,2061,77903,1982063,75226827 -2k5/2P3b1/4b3/1p1pPP2/1p6/8/4r3/3K1n1q b - -,40,144,5362,22408,814651,4490635 -2k2b1r/1q1bpNp1/rp1p4/n1p4p/1PPPPpn1/RN4PB/4KP2/B3R3 b - -,40,1427,53852,1935896,72671687,2619575297 -1n3rk1/7r/1pb4p/p1P5/3b3p/4Pp2/5KB1/1N3RR1 w - -,13,431,7113,246300,4744141,167902984 -Q7/q2bb1k1/pp2p2B/PPp1Pn1p/4B2P/3KP3/8/4NN2 b - -,5,169,3574,111912,2594887,80897730 -8/6kN/P3B1P1/3p4/8/4p2P/8/2RKN1b1 w - -,27,191,4892,38593,1043714,9820102 -rnbq1b1r/ppp2k1p/5n2/3pp1p1/P1P2p2/R2PB2P/1P1QPPP1/1N2KBNR b K -,46,1319,58968,1756740,76415132,2348552017 -r1bq1b2/p2n1kp1/1p1pp2r/1Pp3pp/P1KP1P1P/4B2R/2P1P3/RNnQ1BN1 w - -,26,845,23018,726519,21042171,660088364 -7Q/4k3/8/1P1P4/2nP3P/8/4K3/1N6 w - -,25,219,5585,44503,1166173,9085742 -3nb3/8/4p1k1/4P2p/Qp2P2P/4K3/N5B1/8 b - -,13,327,4300,110903,1516359,39921320 -r1b4r/6kp/4P1p1/pp1p1p1R/Pb6/2p3P1/R2B1PP1/3KNq2 w - -,25,772,17931,591238,14012037,481367632 -8/P1n5/1k6/2R4n/1p1N4/7P/2B2K2/2R5 b - -,15,670,9108,392822,5325073,224075086 -3R4/k3n3/3PK2N/1p1R4/1pq4P/1P6/8/r7 b - -,38,760,25465,560729,18393223,423490504 -1rbqkbr1/p2p2pn/1p2p3/2P5/P2P2Pp/2p4P/2P1P3/RNBQKBNR b K -,25,618,16927,432781,12631060,342406634 -r1bqkbnr/3ppppp/ppn5/2p5/1PP3PP/4P3/P2P1P2/RNBQKBNR b KQkq -,25,750,19612,596607,16583854,519099029 -2b1R3/7n/r6k/P2p1p2/1p3PPp/1P5P/8/3K1n2 b - -,23,402,8652,139597,3061530,48243528 -6n1/5Rp1/6q1/8/4b1k1/1K6/8/8 w - -,20,604,9726,320491,4857856,164652963 -5b2/r1B5/nP6/pP2P1k1/2P1B1p1/1N1b2P1/5K1P/1R1r3R w - -,36,1037,33464,1007345,32489166,994781401 -1Q6/3P4/p4k2/P3p3/n1p3B1/2N1b3/8/5K1R b - -,21,1001,15414,699030,10454319,461788864 -rn2k1r1/pb2ppb1/1N4p1/1qpP3p/2P2P2/P3P3/RP2K1Pn/2BQ2NR b q -,41,1176,47000,1400907,55129459,1695370704 -4nk1r/4q2b/1p2p1p1/p3B2P/4BP1P/R3Q3/1P1N4/1N3K1R b - -,26,1411,35388,1836102,46655699,2356655415 -Q1bq1b1r/6p1/np1pkp1n/2p1p2p/3P3P/NpP1P3/P3NPP1/1RB1KB1R b - -,31,1081,31054,1110407,32579451,1185865075 -R7/6p1/7n/qK2k3/4b3/8/8/8 w - -,3,93,1049,26563,367922,9699030 -8/2r2P2/2R5/8/1pQ1B1Pk/8/1b2K3/8 b - -,21,910,18641,825571,16838924,751099771 -rnbqkbnr/ppp1pppp/8/3p4/1P6/5P2/P1PPP1PP/RNBQKBNR b KQkq -,28,559,16313,359803,10912306,261001148 -3b2n1/8/B4n2/1pkp1P1p/P3p3/1Pp4P/2R4R/3K2N1 w - -,25,466,11620,228709,5759103,117453785 -3R1q2/4k1p1/8/8/b1N1KP2/6Pn/8/8 w - -,28,667,13525,347610,6680147,180577776 -r1b1kbnr/1p1pp2p/2n5/pq2Qpp1/2P2P2/4B1PN/3NP2P/R3KB1R b KQkq -,35,1470,49785,1987908,67202872,2612892112 -1N6/6k1/8/6P1/2r1B3/8/K4R2/3bN3 w - -,38,793,23356,491920,14023896,296229352 -rnb1k1nr/2ppbpp1/1p3q1p/pQ6/NP1p1PP1/4B3/P1P1P2P/2R1KBNR w Kkq -,38,1180,43117,1463855,53998675,1921418889 -1Nb1kb2/2B5/P3p1p1/3PP1rp/2P2P1P/6r1/3R4/n1K4R b - -,28,773,22291,626710,18423394,523860688 -rnb1k2r/p2p1p1p/1p6/6p1/1bPq2P1/1PNPP1Bn/P2K3P/R2Q2NR w - -,29,1162,31989,1259827,36592765,1428827620 -1r6/2k4p/7P/8/8/R5b1/1p6/7K b - -,30,426,10979,152378,3913197,55332310 -2b5/r2pn2r/1Nn1k1p1/pP3pQ1/P2p1P1P/8/2RBP3/4KBNR b K -,23,883,18650,726827,15965598,627965655 -1rbk3r/1p1p4/p1Bb2Q1/1q2P2p/5p1P/1PP1nPP1/P2K4/RN4NR b - -,41,1319,46733,1484450,51612126,1637648054 -b1kr1b1r/3pn1pp/2p1p3/p4p2/pP2P1P1/N5P1/1BPP4/RN1Q1BKR w - -,40,812,32223,701817,27732124,641547093 -7R/P7/1P4P1/8/1r1p1k2/3P1b2/7K/3N4 b - -,22,508,10400,242155,4908458,117809037 -7k/3r3B/6K1/P7/1p6/R6p/3b4/6N1 b - -,22,341,7767,135330,3048232,57796923 -2n2k2/3bp3/N7/p6P/4K3/R4P1p/5r1Q/1r5n w - -,31,1182,32090,1157578,31817796,1110077969 -rnbq2nr/ppp1kppp/3pp3/8/1b1P2PP/2N5/PPP1PP2/R1BQKBNR b KQ -,31,767,23306,634738,19587475,571077765 -rq5r/pkp2ppp/1pn1pn2/3P4/Pb2PPNP/6P1/1P1Pb1B1/RNBQK2R w KQ -,30,1399,42661,1903821,60254929,2595002236 -rnbqkbnr/1ppppppp/8/p7/2P5/P7/1P1PPPPP/RNBQKBNR b KQkq -,21,441,10227,242685,6164778,161038368 -4bB2/2k5/P6P/2K1P3/6P1/8/8/8 w - -,11,118,1657,17461,271203,3013892 -R7/4k1p1/8/4K3/b3pP2/N2q2Pn/8/8 b - -,36,580,17863,291708,8811805,145283948 -r1b1kbnr/1p1pp2p/2n3p1/pq2Qp2/2p2P2/3PB1PN/4P2P/RN2KB1R w KQkq -,42,1425,54171,1810734,67006755,2245480598 -5r2/1k6/4P3/r2P2pP/1P2N1p1/8/nK6/8 b - -,33,540,14857,222436,6016135,85960459 -r5nr/p1p1kpq1/1Q4pp/1p1p2P1/PnPP3P/1B2P2b/1P1K1P1R/R1BN4 b - -,41,1370,47361,1548791,52859634,1723036267 -rRb5/2b3kr/3pP3/1P1NN2P/p3nP1P/8/p7/1KB4R w - -,4,120,4143,115424,3977857,110867492 -2k1nb2/8/3p4/3P1bp1/pNP2PPp/4K2P/2NR4/b5RB b - -,28,846,22764,677190,17633051,522450960 -rnbqkbnr/p1p1pp2/3p2pp/1pP5/2N5/8/PPQPPPPP/R1B1KBNR b KQkq -,28,966,26087,909494,25244240,886580647 -8/2k5/4p1B1/4P2p/4P2P/1K6/7N/1q6 w - -,4,100,860,19828,193909,4405789 -rnbq1b1r/p1pkpppp/1p3n2/3p4/4PP1P/6P1/PPPP4/RNBQKBNR b KQ -,28,912,24691,797284,22638722,736695267 -2r3k1/3P1b2/2n4r/pP3pp1/P4PP1/b2RPRK1/8/8 w - -,25,934,23302,871867,22513509,832825821 -rN6/5Nk1/3P4/pp6/3KB2p/P6P/1P1BP3/R5r1 w - -,48,966,40925,813428,32020763,638554794 -5k2/rp6/Pb3B1r/R1npp1K1/8/6P1/1p1N3P/4N3 b - -,30,730,22270,557140,17811926,455948027 -r3k3/n6Q/p2p4/P1pP4/8/P2KBB1N/6pR/b7 w - -,42,666,27388,495293,20102634,394609718 -rn6/p2p1q2/1pp1p1pk/4Rp2/P4P2/N2Q1b2/3K1PB1/2B3N1 b - -,25,1119,28401,1178757,30757081,1224567294 -5kn1/8/3P4/5P2/p1R1N1pb/P2K4/r7/5N2 w - -,26,544,13161,271652,6567870,137840723 -r1bqkbnr/p3p3/2n2p1p/1pppP1p1/P1P4P/NP4P1/R2PNP2/2BQKB1R b Kkq -,35,1060,36563,1158956,39629499,1311334609 -1nk2Q2/4R3/8/7K/4P3/8/8/8 b - -,0,0,0,0,0,0 -6b1/4bk2/1pq1p1pr/p2n3p/P2p1PPP/1QN3N1/1P4BR/R3BK2 b - -,40,1530,58138,2299474,83450563,3390125572 -8/5k2/8/N7/6Pb/3p2B1/5K2/8 b - -,14,184,2480,41627,586258,10217133 -1n5r/7k/1p1Bbp1P/1P1p2R1/1p1p3N/5B2/7K/1r6 b - -,29,890,24386,694893,19304411,532797258 -q5n1/p6r/P1P2P2/Bp1p2pk/3P3p/5b1P/1R3N2/1Q4K1 b - -,27,946,25033,883437,24187126,855501321 -3k1Q2/b7/4P3/8/8/8/4B1P1/3K4 b - -,1,36,328,10896,102490,3304472 -1k6/2r5/P2N4/1p6/4r3/1p5K/8/2b5 w - -,12,406,4261,138298,1460739,46319109 -6k1/1b2B3/8/8/3p3b/6p1/K5P1/8 b - -,16,201,3454,41414,746655,8875306 -8/8/bK6/4q3/P5k1/8/7R/2B5 b - -,37,685,21108,395737,11679820,223814260 -8/n2r4/2k2pRp/4b2P/P4N2/3P4/4K3/4B3 b - -,26,712,16950,448597,10646679,278926116 -8/1r3P1k/4b3/1rp2P1P/8/6P1/7p/R6K w - -,23,554,11092,277220,5548946,146574409 -8/4B2Q/2k1p3/3p3P/2pP3b/2RB4/8/K7 w - -,34,381,14020,165403,6249571,73699685 -r3kbnr/p1n1p1pp/1p1P2b1/8/2Pp1P1P/P2P4/1N2P2R/R1BQKBN1 w kq -,28,672,19996,502281,15729910,409308887 -5Br1/3k3p/7P/2R1R1pP/2rp1P2/2Np4/6K1/2B5 w - -,42,546,20490,335448,12321116,231896963 -8/5B1n/6nR/P4Pbp/1p6/k6P/5R2/1K4N1 b - -,20,613,10577,324412,5631263,173284157 -3kN3/1B4BQ/7R/1p2p1P1/1P6/p5R1/8/1b4K1 b - -,12,569,6512,306036,3505145,161558487 -1r6/1k2b3/1p3R2/1P3p2/p3p3/6K1/PN2R3/1n1B4 b - -,24,630,14908,406927,9721658,275154723 -1B6/5n2/5k2/5P1P/5n2/5p2/1rK5/6B1 w - -,4,118,1806,45083,746842,17838372 -k4N2/r7/1qP1K2n/1p1P3p/1p5P/1P4R1/8/4R3 w - -,30,885,22839,630763,15255615,423196763 -r3k2r/1b1nb2p/p1p3pn/3Np3/1PPp1B2/7B/P2KPq2/RQ4NR w kq -,39,1652,60099,2495117,92564372,3777778288 -rn2kbnr/p1p1p2p/4Bp2/1p4p1/1q2P1b1/N3Q3/PP1P1PPP/R1B1K1NR b kq -,33,1229,39862,1457212,47726366,1723858328 -r7/3k3p/8/1p3pp1/4r1PP/3n1K2/4R3/8 w - -,15,697,9944,403128,5913187,221422631 -rnbqk2r/1p1p1pbp/4p3/p1p1Pnp1/2PP2P1/5P1N/PP1K2BP/RNBQ2R1 b kq -,33,958,31368,961184,31525191,1007681445 -2qnrb1r/ppp1k2p/2Bpbp1n/2P1p3/P7/BP4PN/3PPP1P/RNQ1K2R b K -,30,1019,30294,1048072,31618668,1112181030 -rnbqkb1r/pppppp2/7n/6pp/3P4/4PN2/PPP2PPP/RNBQKB1R w KQkq -,32,697,23208,554289,18947957,489300094 -3rnbr1/3kp2p/7n/p1p5/1p3p1P/2Pp1R1K/PB1N4/RN3BQ1 w - -,33,886,28796,806953,27117594,784756864 -8/8/Pk6/2p5/P1P2p2/5N2/6K1/4R3 b - -,5,142,656,16644,82509,1926583 -k7/8/4P3/2b2Q2/8/3K4/6P1/5B2 b - -,14,393,4117,122141,1289831,38400297 -b2r2r1/1k4N1/p1p2nP1/Pp5P/1P4R1/1P5P/6B1/1rB1K3 b - -,30,568,16352,350927,10264951,235133668 -2k2r2/8/r3P3/1P1P2pP/4N1p1/8/nK6/8 w - -,17,431,6641,166016,2435861,59924677 -3k1Br1/7p/7P/2R4P/2rp1Pp1/8/N1Rp2K1/2B5 w - -,29,575,17181,366528,10875998,246636754 -8/B7/2R4P/8/3P4/k1bQ4/8/1K6 b - -,3,106,739,28131,215180,8403234 -r3q2r/pb1k2bp/P1p2p2/3pp1B1/1PBPP1n1/6P1/1P3P1P/1N1K2NR b - -,37,1195,43045,1350369,47690470,1472504560 -2k5/2P5/5bp1/6rp/3pQ2P/1RR2nB1/8/3K4 b - -,22,1001,18918,815067,15873364,667881381 -8/4k3/7R/1p4r1/r5p1/n2K4/8/8 b - -,27,451,11739,176745,4712478,69353056 -4N2k/8/7B/1p1pP2P/P4R2/1R1pn3/b2K1PP1/8 w - -,37,481,14795,187417,5842712,72778841 -4Nk2/8/4R1b1/1B4P1/1P6/p5B1/5K2/7R b - -,12,624,6810,328088,3779040,172471084 -r1b1kbr1/pppnqpnp/3pp1p1/8/1P1P2P1/B6N/P1P1PK1P/RNQ2B1R w q -,29,774,21677,596516,17351670,494344724 -8/8/2K5/5k1r/7p/p7/7b/2R5 b - -,21,325,6740,109143,2394785,38237850 -r2qkbnr/2p2p1p/ppnp4/4p1p1/1P2b2P/5PP1/P1PP4/RNBQKBNR b KQk -,37,1093,40014,1182471,43134738,1305291986 -5b2/7r/2k2B1p/5p1P/P4N2/n2P1K2/8/5R2 b - -,23,725,16040,486279,10993373,323027926 -rnbq1b1r/pp1pp2p/2p1kp2/6p1/1P1PP1n1/P1NN3P/2P2P2/R1BQKB1R b KQ -,25,878,20987,745935,18687529,675473029 -3N4/5rk1/2B5/Pp1R3p/5b2/2K5/7B/8 b - -,28,784,19190,566712,13132951,399153850 -2K5/8/8/1k5P/3b4/1b6/8/R7 b - -,27,482,11266,186926,4094792,67354510 -6R1/7n/2r1kbp1/BP5r/5p1P/p1P5/2N5/2R3K1 b - -,37,1113,35010,1058997,32221473,980836152 -r3kb1r/1p1b4/1qnpp2p/2p2pp1/1nQ1P2P/PNPP1P2/1P2N1P1/R1BB1K1R b - -,41,1586,62376,2469594,96645684,3870626192 -8/2k5/8/1pq5/1p1p4/5B2/4K3/5n2 w - -,14,371,4346,118591,1264240,34959161 -2k4n/8/8/8/1K6/7r/8/8 w - -,5,100,540,11082,59601,1245872 -rn1q1b2/p2p2p1/1pp1pnk1/3b1p2/PP1R4/5R1B/3PPP2/1NBQK1N1 b - -,32,984,30510,961303,30653795,995005332 -8/8/7k/8/3Rn2p/1P6/2K4p/8 b - -,18,331,5415,95261,1539051,26364788 -rn1qkb1r/3pp2p/bPQ3pn/p4pP1/1P6/5N2/P2PPP1P/RNB1KB1R w KQkq -,41,889,34597,861183,32791389,904301020 -3rkbr1/5p1p/2P2nR1/p3p3/pP3n2/1RP4b/3B1P1P/2NK1B2 w - -,29,1307,37340,1571154,46165977,1861963572 -5N2/k5b1/8/1P6/1K5P/6R1/5n2/8 w - -,25,422,8951,149891,3134855,51900083 -rn1qk1nr/pb1pppb1/2p5/Qp4p1/8/NP1P4/P1P1PPP1/R3KBNR w KQq -,38,1264,45045,1483418,52731892,1750762059 -2n3Q1/3k4/8/1PRP4/3P3P/8/4K3/1N6 b - -,6,221,1217,44317,289706,10297505 -1n6/Bb3r1k/6p1/1P2pp2/2pp1PpP/4PN2/1p5N/4RR1K w - -,19,603,13173,410399,9993437,307704928 -8/r7/1r6/k7/N2P1K2/P7/R7/8 b - -,26,488,11883,226016,5494248,106742870 -rnb2b1r/3p4/pp3p1k/1P1p3p/3p2PN/2P1q1K1/4BB2/1R3R2 w - -,5,149,3937,132640,3731956,127673253 -k7/4r3/8/8/2pK4/2P5/1N6/8 w - -,7,120,1099,17357,174546,2772551 -k7/1r6/pQ1B4/Pp6/1P6/3p3b/3K4/R7 b - -,16,577,8499,300914,4677446,164937926 -2nN4/4r1k1/2K5/8/5Bp1/6P1/8/1b5R w - -,28,643,15198,361727,8429692,202287217 -3N2k1/8/7P/P3P1B1/1p4P1/1K2p3/6b1/8 w - -,18,226,3920,48260,856465,10821624 -1n3k2/3q4/3r4/4KP1p/8/b4R2/8/8 w - -,13,497,5640,223360,2620173,103070921 -rb6/r6b/8/p1p1P3/P1N4P/1p1kp3/3P3R/3K4 w - -,16,299,4863,112040,1870449,47849573 -3rk1r1/2p1ppbp/nN3npB/pp1p2q1/1P1P2b1/P1P2Q2/5P1P/1RN1KB1R b - -,40,1532,60736,2289006,90467175,3413687456 -8/1pp3R1/1k4P1/1p3p1p/5P2/5r1b/n2N4/3Kn1N1 w - -,17,410,7322,174492,3204591,75799829 -8/8/1K5B/1b2P1k1/P3q3/8/5R2/8 b - -,5,138,4469,96066,2818635,57168676 -2b2bn1/1k6/3p3b/3P1Pp1/p1P3Pp/3BK2P/2R2N2/4N1R1 w - -,25,365,9418,157288,4171305,74415101 -rnb1k1nr/2pp2p1/1N3p1p/p1b5/1PQp1PP1/4B2P/P1q1P3/2R1KBNR b Kkq -,44,1392,52786,1762950,64970315,2247274662 -6n1/5r2/r3kp1p/pNb3BP/P5P1/3P1P2/2p3BK/6R1 w - -,28,892,23625,729621,19055801,588131596 -bbn4r/2N5/1q5k/p2P4/2PBB2p/4PP2/P2K4/2R2Rr1 w - -,41,1677,61763,2517090,91273979,3719976204 -3k1b2/rp3pr1/1n1p2pp/pPp2P1R/3P1p2/P1N5/1BPNP3/3RKB2 w - -,31,763,24361,578964,18836731,445066262 -bk1q4/3n3p/2P5/P2p4/2Nr2n1/3p3K/1B1P4/8 w - -,15,475,7550,238998,3869119,123754382 -1b6/5b2/8/3k3P/5r2/r7/4p1KQ/8 w - -,9,403,6027,212940,3704648,123006289 -8/6k1/1N1P1n2/1b3P2/p3N1p1/P1R1K3/r7/4b3 w - -,24,810,17295,548411,11788213,358694024 -6b1/5kP1/8/1P3B2/3B4/8/p4K2/7R b - -,7,298,3402,123478,1831780,63011235 -5k2/4Q3/3R3P/1pp2r1r/8/Ppb3KB/2N3n1/8 b - -,2,71,2052,62588,1794567,56488942 -7k/8/8/1p4n1/8/8/nK6/7b b - -,20,115,2348,9102,189390,889983 -8/5B2/8/4k3/1p6/3p4/8/7K w - -,12,99,1177,10020,121190,1111155 -5n2/7k/4p1p1/7p/1p5P/7r/1R6/4bK1B b - -,23,433,10004,190447,4481873,87980730 -7k/R7/5PP1/2p4P/4K3/8/8/5b2 b - -,9,166,1421,26060,228912,4258407 -8/1pr2k1p/7n/4pPp1/2pB2b1/4R1P1/1K3NBP/6R1 w - -,45,1032,42488,1015801,40285359,986127710 -1N1k4/6b1/P3p1p1/1bPPr2p/3BR2P/8/3K3R/n4r2 b - -,37,893,30624,770433,25561766,660645331 -8/6Bp/8/8/1N3Pk1/BR1R2p1/6Kr/8 w - -,2,40,1157,17927,552360,8139633 -7r/3r1b2/2B2k1p/P1pp2n1/3P1K1R/1PB1p3/5R2/8 b - -,33,992,28757,856608,25350310,752860773 -8/q7/5k2/p5r1/PP1rp1P1/1K1P4/2RNp1B1/1n2N3 b - -,41,952,37264,889038,35400629,861140794 -1rbk2nr/pp1p1ppp/n1p2q2/4p3/P1B1PP2/b6P/1PPP2P1/RNBQ1KNR b - -,34,1152,39454,1327868,46100473,1553838762 -4N3/1B2k1B1/8/1p2p3/1P2QPr1/p5R1/b7/1N4KR b - -,18,791,14020,656951,11892440,572375025 -8/3q1k2/2n5/4KP1p/3r4/8/7R/8 w - -,0,0,0,0,0,0 -3R4/4k1p1/8/8/b4q2/N2K2Pn/8/8 w - -,19,651,9689,317229,4972678,159077453 -1B6/8/1r3k2/4nP1P/3B1n2/2K2p2/8/8 w - -,13,302,4628,114794,1911467,47674900 -3n4/2k2b2/8/3p2p1/8/3K4/8/1N6 w - -,9,152,1463,25573,252916,4522589 -4k3/8/4r3/4N3/P7/1P1B1PRp/2K4P/8 w - -,32,383,11310,153991,4521475,62497662 -r1b3r1/1p1k4/p2b1Q2/2p1P2p/q4pnP/1PPK1P2/4N3/RNR5 w - -,36,1063,32896,975145,30714878,917704084 -8/K2kN3/p6r/p7/P3N3/8/8/8 w - -,17,279,4578,70708,1075219,16800265 -4k1r1/8/8/2B1Nnp1/ppp1bP2/b3p1P1/K7/R4BR1 b - -,29,793,23441,670288,19728722,583424868 -3k3r/1R6/2P4n/3p1PN1/8/5NP1/2n1K3/4b3 b - -,22,655,13696,386591,8599378,232218514 -k7/Pq5p/2nB4/3p4/b7/3p4/3nN1K1/8 b - -,38,848,31085,603657,21712541,392603697 -5R2/3k4/8/5P2/3B4/4r2p/8/2NR1K2 w - -,30,347,10613,133082,4237458,57436487 -1B6/5n1k/4n3/5P2/7B/2K2p2/7r/8 w - -,20,565,10946,284613,5454453,135867338 -r1bq1bnr/pppk1pp1/3p4/4n2p/3PPp1P/N4PP1/PPP1K3/R2Q1BNR b - -,34,891,29437,820131,27167103,791052140 -2kr3r/n7/p7/PP1BB3/7P/1P6/7K/2N5 w - -,35,607,18064,370464,10278344,234739487 -rnq4r/3kn2p/1p2p1p1/8/P2B2P1/7P/3bPKb1/2Qr1RNR b - -,55,1644,82248,2420572,117705403,3548125247 -4k1r1/N7/8/6p1/pBp2P1n/4p1P1/Kb4b1/R4BR1 b - -,33,911,29266,841331,26463521,789946768 -rnbq1bnr/pppppk1p/6p1/5p2/P7/1PN5/2PPPPPP/R1BQKBNR w KQ -,24,597,15513,400297,11177282,301418941 -rnNk4/6rb/1p2q3/6pp/Qb1PPP2/P3BN1P/1P4K1/1b1B3R b - -,58,2426,124628,5113041,248149959,10082275414 -6n1/2p1k2r/P1r4p/P2p1ppq/1n1PPP1P/1P6/3K4/RBBNRb2 b - -,47,990,41283,922744,37549394,881317498 -8/2Nr4/4N2k/p4p2/P1K2P2/8/6p1/8 b - -,19,276,5319,77626,1595557,22300511 -3R4/4r3/1B6/8/1N2kP2/7p/4KR2/6b1 b - -,14,448,6748,218327,3579119,115245743 -1k3r2/6p1/4P3/r6P/1P1P2p1/3K3N/n7/8 w - -,15,509,6757,211370,2824791,83992717 -2r5/8/5b1k/rp6/2Np2PB/1R6/5K2/1N2r3 b - -,44,1164,46155,1156641,43837150,1097353371 -8/7k/B7/6np/7p/3pP3/8/bR4K1 b - -,19,391,7410,152733,2939900,60909154 -r3k1Br/1bp1p2p/5bp1/ppP1P3/P3NB2/1PN2P1P/3K2P1/R3Q2R w - -,53,1250,61848,1456522,70166848,1660740224 -r1bqkbnr/p2pppp1/n7/1pQ4p/7P/3P2P1/PPP1PP2/RNB1KBNR w KQq -,47,1005,42581,1046990,42785749,1163529772 -6R1/4r2k/3Q3b/p3p2p/PR2PP1P/2N5/4K3/6N1 w - -,58,786,41191,584804,28183538,420256066 -rn4n1/4b2r/p2ppk1p/1b1P1pp1/pP2P3/3R4/2K1NPPP/1N2B2R w - -,37,888,29617,753764,24093770,640106984 -6B1/8/8/8/6k1/1p1p4/6K1/8 b - -,7,89,720,8957,80437,1023277 -8/8/P3R3/2p5/k1P5/5p1N/7K/8 b - -,5,105,684,13855,107005,2123820 -1r3kr1/1bpqp2p/1p2Bbp1/p3P3/P1P1NB2/1PK2P1P/2n3P1/RN1Q3R w - -,48,2020,86389,3381653,141417069,5299634862 -8/6k1/8/2P5/B3N3/8/1K6/8 b - -,7,161,752,16262,85768,1799356 -8/kr6/8/8/2P3K1/8/8/8 b - -,17,138,2346,16354,279667,1943696 -8/p4k2/P7/1p1p4/3P3p/7P/4NK2/B2q4 w - -,10,241,2055,46659,438424,9568325 -r3kN2/2qb1N2/3P4/pp6/4B1rp/P3Q2P/1P1BPK2/R5R1 b - -,35,1978,57100,3040888,93773040,4818741133 -6nr/2p3r1/P2k2Pp/P2p4/1n1Pp1bP/1P2K3/BB6/5RR1 w - -,26,708,18306,485736,12711927,337700354 -b5k1/7R/1P2B3/p5P1/P3Pp2/8/1b2K3/8 b - -,2,56,824,20306,313532,7404687 -rnb2r2/1pppqk2/1b2p2n/pP3ppp/P2PP3/5PK1/1BPNQ1PP/R4BNR b - -,34,918,31948,885742,31053279,891669868 -1rbqkbnr/p3pppp/np4B1/2pp4/P1PP4/4P3/1P3PPP/RNBQK1NR b Kk -,25,958,26011,988594,29091794,1100159428 -r1b2b1r/2Bpk2p/1p2P1p1/p4p2/P4q2/2p3P1/Q3KPPR/R3NB2 w - -,32,987,27436,837281,25533543,784800774 -rnbqkb1r/pp1pp2p/2p5/7n/P7/1QPp3n/1P1PNK1R/RNB5 w - -,6,152,4253,115747,3282357,96112354 -8/Q1Nr4/6Bk/8/1p5K/7p/8/8 b - -,16,482,7402,228017,3392070,104970033 -8/k7/8/3BK3/3r3b/6p1/8/8 w - -,17,342,3990,84951,1007148,22319184 -3q1bn1/2p1pkp1/rp3P1r/p2p3p/2P1bPPP/N2P3R/PP2K1B1/R1BQ2N1 w - -,38,1349,49715,1723698,64102338,2207648923 -7k/8/3K4/2P5/8/7p/5R2/7b w - -,20,194,3625,42742,783158,9796038 -1k2nb2/8/3p4/3Pbbp1/p1P2PPp/3NK2P/2NR4/6RB w - -,35,973,29936,799546,24115604,625462056 -rn1qkbnr/1b1pp1pp/p1p5/6B1/2P5/7B/PP2PP1P/RN1QK1NR b KQkq -,18,668,13538,508673,11617262,438852836 -2r5/n3b1kr/6p1/pb1P1p2/PPNp1P1p/4P2Q/5KPn/R1B3R1 w - -,32,1344,42018,1653997,52797150,2007683363 -rn1qk2r/p2pn1p1/b1pb1p1p/1p1Qp3/4P1P1/2P4P/PPKPNP2/R1B2B1R b kq -,26,895,22503,757692,19795572,662463023 -k7/2K5/5R2/3b4/7P/b7/8/8 b - -,20,360,6017,99911,1696024,27422083 -r2bk1r1/p1p3pp/n2p1p2/1N2P1B1/P3P1b1/2P5/1P3PPQ/2R2KNq w q -,35,1105,35094,1103649,35143317,1115586701 -5B1r/3k3p/4p2P/2RB2p1/1r3P1P/2Np3K/8/2B1R3 b - -,22,982,19695,855778,17573720,751781124 -1rbkr3/p1p1p2p/Qpqn3b/1n1pP1p1/1PP2pP1/3PBP2/PN2N2P/2R1K2R b - -,31,1297,41123,1638918,53796012,2069694436 -2R3k1/1b1Q4/1N4p1/1P1p1p2/Pp3PnP/3pR3/4PNB1/4K3 b - -,1,46,606,24756,332967,13055904 -r3kbnr/p3qbp1/n1pp1p1B/P3p2p/Rp2P2P/1P1P2P1/2P2P2/QN2KBNR b Kkq -,28,969,28436,986483,30101636,1047754979 -5n1k/8/4B1p1/4p2p/5b1P/5K2/8/4r3 b - -,24,287,7074,77299,1931784,21250383 -7r/p1kn1p2/1pp1p2b/8/1P4K1/1Bn2N2/P4r2/4R2R b - -,49,1650,78301,2498197,114269891,3529856770 -rn1qkb1r/1b1pp2p/1PQ3pn/p4pP1/1P1P3P/5N2/P3PP2/RNB1KB1R b KQkq -,22,919,22550,892418,24439882,940901546 -7r/4kqBb/1pB1p1P1/1N6/p4P1P/3R4/1P1N1Q2/5K1R w - -,62,1129,65855,1328024,73585780,1640477190 -8/3kB2Q/4p3/2np3P/2pPB2b/2R5/8/K7 b - -,18,623,9723,347199,5405039,196964151 -Nb6/4B1nr/1p5k/5P1P/1pP3pN/p4R1P/Pq6/R2K1B2 w - -,28,862,19781,610219,15086160,470613082 -5nk1/2r4r/8/3R3p/p6p/3pPB2/1b3K2/R7 w - -,34,1176,37276,1234447,37884502,1236534375 -q3kb1r/3bp1p1/rp1p4/n1p3Np/1PPP1pn1/R3P1PB/3NKP2/B3R3 b k -,43,1623,67232,2488661,100231164,3664321079 -6r1/1kb5/p2B2PQ/PppR1p2/2r5/RP5b/8/4K3 b - -,34,1106,35386,1197581,36887631,1282010374 -Nb6/4Bqnr/1p5k/5P1P/2P3p1/pp3N1P/P2R4/RK3B2 b - -,30,1101,32798,1105721,34068476,1090459465 -4k1B1/7r/2p1pbp1/ppP1P1Bp/P2Q4/1PNRKP1P/6P1/6R1 w - -,45,834,36659,595169,26274204,422317085 -rnb1k2r/1p1p1ppp/pbp2n2/4p3/P4PP1/1qB1P3/2PPN2P/RN1QKB1R w KQkq -,27,1093,31648,1264174,38255332,1502484971 -2b1k1r1/p2p2b1/B3p3/6pn/Pr1P2Pp/2p4P/R1P1P3/1NBQ1KNR w - -,30,903,25683,773417,22711130,686020773 -7k/R7/b4PP1/2p2K1P/8/8/8/8 w - -,18,130,2303,19191,352746,3081030 -1r2b2k/8/1p3R1P/1Pnp4/6pB/3p2K1/1p6/5B2 b - -,25,526,12928,294252,7481103,176354611 -3k4/8/1n6/1P1P2n1/3P3P/2p1K1R1/6Qr/1N6 b - -,22,552,12514,321004,7218701,190608845 -8/P6B/7k/8/1p2N1K1/2r4p/8/8 b - -,17,305,5007,98905,1622340,34680708 -r1b1k2r/ppqp1p1p/2nP4/2pN1Pp1/4p1P1/1Q5P/PP1BP3/R3KBNR w KQkq -,44,1128,46927,1163424,46376755,1148850016 -3r4/p1p3p1/2r1P1kP/P1n5/2Rb2P1/1P1b2N1/3K4/7N w - -,22,914,19692,787111,16827842,653239655 -1r2bk2/Np2q2r/N2p3n/B7/P1P2pQp/3PPP2/1P4PP/2R1KB1R w - -,44,1402,58924,1947841,80884885,2734593305 -8/B7/6QP/1k6/3P4/2R5/8/1Kb5 w - -,44,360,14873,132490,5327824,48991640 -k7/8/5r1N/8/2pK4/2P5/6r1/4N3 w - -,14,408,5203,141406,1871087,49686347 -3bn3/8/bpk2n1p/3p1P2/P1B1p3/1Pp4P/R3K3/6NR b - -,25,441,10796,218697,5454114,120284482 -8/8/1k6/1pN1q2B/1p1p4/8/2Kn4/8 b - -,34,572,16501,255150,7231284,108220070 -6R1/p6k/P1P5/2P1r3/6BK/1P6/5r2/8 w - -,23,562,11649,270700,5370197,123254397 -r1b1kbnr/p2p1ppp/2p1p3/1p2n3/1PN1P2q/7P/P1PPNPP1/R1BQKB1R w KQkq -,24,931,22709,862035,22967783,862914742 -8/6kN/8/2q1N3/Pp1rp1P1/3P4/2RKp3/7r w - -,19,861,15432,656842,12401507,507590831 -rnb1kb2/p2p3r/6pp/1pNppp1P/5q2/P7/1PPBPPP1/R2QKBNR b Qq -,37,1231,44605,1487719,52687565,1777418528 -5n1k/8/2B3p1/4p2p/4r2P/4K3/8/4b3 w - -,4,74,841,16841,191612,4049343 -2b1kb2/2BNp3/P5p1/3PP1rp/2P5/1r4P1/3R1P1P/n1K4R b - -,27,780,20693,592040,16201414,462622167 -7k/8/1p3nRP/1b1B4/5K2/8/2b5/8 b - -,26,660,15007,352116,7595389,173968704 -5N1k/5n2/1N1pQ3/5r2/P2P3p/KPp2P2/7P/5B1R w - -,40,663,26677,431773,17183215,281009731 -2n1k1r1/rp2bp2/7R/pPPp1Pp1/5p2/P1N1N3/2P1P3/BR2KB2 w - -,39,883,32399,749768,26913412,636212188 -3k3r/7R/8/2Pp1P2/p5n1/3K1N1N/3b3P/6r1 w - -,28,831,20428,610082,14446920,431344663 -8/7k/3n4/7p/8/1P1K3p/7R/8 b - -,14,233,3021,50185,616482,10648711 -2b1kb1r/r1p4p/p1n1p3/1p3qPP/2Pp1B2/1N1P1K2/PP2Bn2/R2Q2N1 b k -,45,947,41393,992882,42266679,1117141671 -4n3/1k4N1/8/p3p2p/2B4r/5K2/1b5B/1N1r4 b - -,38,875,30501,673272,23120669,507752671 -bnn2k2/8/1B6/P1p5/2PpP1KN/1p1Pb3/8/8 b - -,24,358,8122,122126,2878147,44513305 -8/2P5/8/5n2/8/K5k1/8/8 b - -,15,134,1841,23038,281233,4306463 -B1k5/B6r/p4r2/PP6/1P5P/7K/4N3/8 w - -,27,726,17885,446887,10945503,266046309 -8/r2N3r/4P3/P2bb2P/2pk4/4p3/1p1P2R1/3K4 w - -,24,865,18040,650532,13185490,475581706 -8/3r3n/4k3/1P2b1pr/2P4P/p4R2/8/4N1K1 b - -,35,786,24664,512675,15810487,317181424 -1k6/8/4p3/1B2P2p/1K2P2P/8/8/5N2 b - -,5,95,428,7798,36012,645152 -rn1qk1r1/p2p4/b1p2ppp/1p1Q1n2/1P2PpP1/1P5P/P1KPN2R/R1B2B2 w q -,39,852,31004,713414,25824412,625584619 -r1bqkbnr/p1pp1p1p/2n1p1p1/1p6/1P2P1P1/3B3N/P1PP1P1P/RNBQK2R b KQkq -,33,858,28143,754184,25044456,697052111 -5b2/1q3b1N/1k4p1/2pQ4/2Bp3P/P1P3P1/2NK1P2/2r3R1 w - -,47,1330,54326,1712575,67940119,2226771234 -rnbqkbnr/p1p2ppp/8/1p1pp3/6P1/1P3P2/P1PPP2P/RNBQKBNR w KQkq -,21,798,17622,654393,15501201,570712190 -3K4/8/P5b1/8/8/5R2/8/4k3 w - -,19,213,3933,46526,868329,10592948 -rnb3r1/pp5p/4p1kb/4npN1/P1PQ1PPp/2P1N3/4P2B/1R1K1B1R w - -,42,1097,46708,1192987,50406362,1303107242 -2r5/5b2/2nP1k2/pP3ppr/P3RPP1/b3PR2/8/4K2Q b - -,40,1079,39905,1107635,39915653,1141507331 -r2b1qr1/p1Bn1k1p/1p2p1p1/2p5/P1bQPp1P/1P3P2/1R1P2B1/2BK1R2 b - -,34,1151,37243,1224535,40373490,1318671318 -1k3b2/4Q2N/8/2pb2pP/2Bp4/P1P3P1/2NK1P2/3r3R w - -,3,66,2869,52188,2199693,40496240 -rnb1qbnr/6pp/1p1kp3/2p2p2/P1p3P1/BQN1KP1P/3PP1B1/R5NR w - -,36,1198,40819,1321505,44174131,1418008478 -5r2/p1qQ1r2/5k2/4p3/PB4pp/1PnPpP1N/1RK3P1/1N3BR1 b - -,39,1155,37366,1189959,39705631,1318058707 -5Q2/3k4/1n6/1PnP4/3P3P/2R5/4K3/1N6 w - -,42,477,19054,210319,7688171,90371215 -rnbqkbnr/pp1p1pp1/4p2p/8/2p4P/NP5N/P1PPPPP1/1RBQKB1R b Kkq -,32,697,22816,543191,18067125,467244712 -q3kb1r/3bp1p1/rpnp4/2p3Np/2PP1pn1/RP2P1PB/3NKP2/B6R w k -,37,1428,49695,1929090,66891548,2602840453 -1b2B3/8/1k6/4p3/5N2/2P5/K6p/8 b - -,15,302,4537,84303,1448252,25929658 -4Qr2/p1q2r2/8/4pk2/PB4pp/1PnPpP1N/1RK3P1/1N3B1R w - -,36,1130,34217,1153685,38123678,1321159221 -r1B2bnN/q1k5/1p1p4/1b1Pp1p1/1p2np1p/2B2PP1/2R5/4K1R1 w - -,31,1031,31090,1113465,33247904,1243114186 -rnbqk1nr/pppp3p/6pB/2b1pp2/7P/2PPR3/PP2PPP1/RN1QKBN1 w Qkq -,30,851,25955,758853,23425844,706424294 -1r1k2nN/7B/3p3b/3Pp3/5R1p/5PR1/5q2/2nK4 w - -,29,1153,25679,1004259,22436705,865416105 -8/8/8/KP6/7k/8/4N3/8 w - -,11,46,514,3080,35446,211869 -rnbqkbnr/pppp3p/6pB/4pp2/7P/3P4/PPP1PPP1/RN1QKBNR w KQkq -,31,904,27146,804926,24515336,748971327 -2Q5/p4r1k/P7/2P5/8/1P6/3R3K/r7 w - -,33,752,22863,482519,14459558,297294492 -r1bq1b1r/p2n1kp1/1p1pp3/1Pp3pp/Pn1P1P1P/7R/2PKP3/RNBQ1BN1 w - -,31,1078,33377,1135849,35562428,1196382222 -8/P7/4R3/2p5/2P5/5p1N/2k4K/8 w - -,25,207,5273,36867,942484,7011491 -8/5k2/Bn3r2/6bn/b2p2r1/2p5/2R5/3K4 b - -,44,396,16254,186089,7771182,105816541 -8/r5P1/1k3q2/8/6K1/7p/4R3/4B3 w - -,27,980,21342,741478,17008312,563194784 -5r2/2b2k2/B5p1/p1Q1p2p/P3PP1P/8/2rp1K1R/2RN2N1 b - -,28,1075,27596,1053994,27572789,1050780957 -rr6/1b1Bb2p/p1p3k1/3Npq2/1PP5/3pB3/P3P3/3K1RNR w - -,42,1458,58530,1968863,78139103,2611554274 -8/r3kb2/np5N/4PP2/P2P2P1/6BK/b1B2R2/8 w - -,25,570,15169,358904,9905868,242485660 -1r2rbk1/np2p3/1P3ppn/2p4p/RP3P1P/3P2Pb/1R1KB3/5q2 w - -,24,936,20877,807762,18617727,722245471 -1k4r1/3q1n2/3N4/Q1PPp3/2P3Rp/K4Pp1/8/6R1 w - -,43,1107,44317,1128050,43684916,1115398177 -r1b1kb1r/pp1pp1pp/n1p2p1Q/8/q2PPP2/4B3/2PKB1PP/RN4NR b q -,29,975,27661,948284,27800329,975421711 -8/2R5/7k/6np/7p/4P3/8/1B4K1 b - -,7,135,1062,25179,210383,4802799 -2b1kb2/3Np3/P5p1/B2PP2p/1rP2r2/6P1/5P1P/n1KR3R b - -,31,774,23167,581884,17493994,448328664 -4n3/3kr1b1/6pp/P3p3/4B1P1/2PPP1nP/1B1Nb3/R3K3 w - -,28,669,18695,483244,13436830,366895496 -2b1kb2/4p1rp/1Bp2np1/Pr1PP3/2P5/6PB/p3KP1P/R1N4R w - -,39,1135,39685,1131467,38179008,1088267916 -2b3q1/p1r1n1p1/P1pp4/1PP2P1k/1B1P3p/1Q2R2P/1R2K3/1N6 b - -,27,1095,29749,1176222,32183221,1249970307 -7r/7p/2bb2kP/p2pP1r1/B1p2P2/2p1B1p1/6R1/3K4 w - -,29,837,21592,622510,15500428,450878880 -2kr1br1/1b6/2p1p1np/P2p1Pp1/p2B2P1/N1P2QP1/3PB3/RN4KR w - -,42,1050,43224,1123507,45755320,1221951635 -r4bkr/p1n1p1pp/3P4/8/2pQ1P1P/P3P3/7R/RbBNKBN1 w - -,47,1098,49816,1187993,53018454,1293686489 -5B2/3n4/3r2k1/1K1N4/8/6Pp/2b5/8 b - -,25,366,9355,145326,3963767,63037563 -rnb2r2/5k1p/1p2p2b/p1P1n3/PQ2pPPp/2P5/4P1NB/3RKB1R w - -,34,1071,33693,1059622,33595958,1058022949 -2r4r/4p3/bq3Pk1/2p5/R4PpP/4bNP1/6K1/7R w - -,30,1455,39071,1823581,48122640,2181518202 -rnbqkbnr/6pp/1p2p3/p1pp1p2/PPP3P1/B4P1P/3PP1B1/RN1QK1NR w KQkq -,23,800,19523,687211,18053564,641924053 -1k6/8/3r1pP1/p1p5/P1P5/1P6/N4K2/R1R5 b - -,17,330,5655,115396,1931372,42446146 -3k3r/5R1p/8/p1Pp1P2/6n1/3KbN1N/2R4P/4q1r1 w - -,31,1079,27683,1004052,25916524,958288476 -1n4nr/2k1q2r/1p6/P2p3p/Rp1PPP1P/1P4PR/3N4/2N2K2 w - -,23,688,16417,500251,12163093,379994302 -4kr1r/2pR2np/1B3p2/Q7/PP3Rn1/2p4q/4P2P/4K3 b - -,29,1065,28107,982786,26625627,910203347 -rnbqkbnr/pppp1ppp/4p3/8/2P5/8/PPQPPPPP/RNB1KBNR b KQkq -,30,860,26337,785252,24602596,754751295 -rn1qkb1r/1b1pp2p/1PQ2ppn/p7/1P4P1/5N2/P2PPP1P/RNB1KB1R b KQkq -,24,894,23506,871466,25027657,927330739 -8/8/P4nn1/1k6/1pR5/7P/2B2K1R/6N1 w - -,32,561,16577,268434,8112857,125633057 -8/7K/2nr3P/8/7k/2p5/8/1r6 w - -,3,117,574,21937,99796,3601636 -8/8/1n3k2/8/3P3P/5K2/8/1N4Q1 w - -,28,268,7061,65855,1771572,16852784 -r1bqkbnr/p1p2p1p/4p1p1/1p1p2N1/1n2P1P1/3B4/P1PP1P1P/RNBQK2R w KQkq -,30,1033,30258,1055955,31780406,1125582569 -8/8/n3kP1p/rp6/6pP/8/2r2R2/6K1 b - -,28,394,10816,147308,4022816,57464767 -8/2p5/1p6/1p3p2/1k3P1p/1n2N3/6K1/r7 w - -,11,250,2619,58772,547214,12056817 -1nbqkb1r/2ppp1pp/1p6/5p2/rP1PP1n1/pB3N2/PBPN1PPP/1R1QK2R b Kk -,30,1013,29863,1011540,30518796,1046605965 -8/7p/8/3N4/5P1k/BR1R2pr/8/B5K1 w - -,39,259,8861,76078,2660489,29319546 -2r5/3n1k2/p2p4/P1p1p3/1R2PP1p/1b1K2QN/B5P1/3N3R b - -,27,955,22557,799309,18633196,666901964 -5r2/b4k2/B5p1/p1Q1p2p/P3PP1P/8/2rp1K1R/1R1N2N1 w - -,37,809,30032,704428,26802731,653218434 -r1bqkbnr/pppppp1p/8/6p1/3n1P2/2P5/PP2P1PP/RNBQKBNR w KQkq -,28,790,22327,619095,18759653,527889811 -r5k1/2q5/1pn1p3/pp1pBpp1/P4P2/3QK3/2N3b1/6N1 w - -,35,1365,44467,1642789,52815130,1873684770 -B7/5r2/p2BN1kp/PP2b3/5r2/3R4/3K4/8 b - -,36,1333,43503,1553201,49509780,1716741170 -7r/k7/6p1/p3p2p/Pn2R2P/2Bp1P2/6KR/8 b - -,21,530,10792,278683,5732021,149360529 -4n3/7R/P1p5/5kp1/r7/1PB5/2N1K3/b4N2 w - -,45,974,36916,781489,26903945,580582342 -1r3k2/Np2qb1r/N2p3n/B6Q/P1P2p1p/3PPP2/1P1K2PP/2R2B1R b - -,35,1471,50685,2125489,73890574,3084751852 -1k6/1P6/8/2P2p1p/8/8/1N4r1/B5K1 w - -,3,41,305,4216,53479,771831 -3K1k2/8/5n2/8/1P4p1/1Nr5/p7/5N2 w - -,11,302,3315,85879,1046502,27169357 -rnbqkbnr/pppppp1p/6p1/8/8/8/PPPPPPPP/RNBQKBNR b KQkq -,21,420,9799,216714,5553969,135553939 -7r/r3k2p/1p2n3/5pp1/P5P1/4K2P/4b3/7R w - -,14,564,8971,345665,5607836,207980606 -2R1r3/1k2b3/1p5R/pP2pp2/8/6K1/PN6/1n1B4 w - -,41,823,27987,597190,19468454,429066708 -1nb1qbn1/r4k1r/pp1p3p/N4ppP/P5P1/1P3N2/2PPPPR1/1R1QKB2 b - -,36,841,27915,688752,23096994,601575307 -7k/8/1p2p2n/Pp2P2p/7P/Q1p1P3/3NK3/4N2B b - -,11,397,4760,156793,2027261,64216220 -2K5/R7/b5q1/P7/8/8/6kB/8 w - -,6,191,2358,73905,1115920,33796776 -5B2/3k3p/7P/7r/5Pp1/2Rp4/N5K1/2BR4 b - -,17,511,7646,237876,3554022,113946334 -1k3B2/1bN5/8/6r1/8/8/4K3/b7 b - -,33,581,17821,299638,8945771,146439344 -r1b5/1pp1n1r1/pk1p1p1b/4P1Qp/5pnP/NP1K1PPR/Pq4B1/4R1N1 w - -,33,1468,39467,1693697,46182148,1946000109 -rnbqk1nr/ppppb1pp/4p3/5p2/2P5/1P2P3/P2P1PPP/1RBQKBNR w Kkq -,28,756,21273,605175,17462818,517991261 -1K2k3/4N3/p7/p7/P7/8/3N4/4r3 w - -,17,288,4440,70733,1062171,16779881 -7k/8/4P3/7p/P3P3/6bN/N7/5K2 w - -,13,160,2351,28685,452248,5652452 -1b3k2/8/1p5N/PP6/2B3K1/5R2/8/2b5 b - -,5,152,2298,66120,1122555,31347850 -3b3r/5k2/6p1/p3p2p/P3PP1P/4Q3/2rp1K1R/2RN1BN1 b - -,33,1113,32787,1139932,32294344,1151368522 -5nk1/7p/r1p4b/p5PP/K4p2/3R4/5B2/8 w - -,27,345,8214,127679,2853072,49835384 -k7/6rr/p2B2P1/PpQ2p2/1P1p4/3K3b/R7/8 b - -,17,593,11473,392916,7981858,266975654 -k7/5n1p/1qb5/P2pnN2/8/3p2K1/3P4/6B1 w - -,20,703,12698,427832,7370514,243134493 -6k1/3Qp3/Nn6/p1K2P1P/8/1b5p/1R1r4/1r5n b - -,44,1172,40637,1129579,37842535,1081971583 -8/2NB1k2/8/2P5/8/8/8/1K6 b - -,6,126,693,13789,70909,1394421 -r6r/pp3k2/3B4/q3p2p/Pb3pp1/1PnP3N/1R1QPPP1/1N2KBR1 w - -,25,1076,27378,1159671,30382685,1273725995 -3rn3/4p1n1/2k5/p4N1p/2B4r/4BK2/1b6/1N6 b - -,36,1182,39369,1186910,40299006,1139785639 -3k4/6R1/8/4P3/1NpK3P/5p2/r7/8 w - -,28,453,11174,167038,3888844,58759951 -1R6/4kp2/4r3/p5rp/1b2p3/p1P4B/1R3P1P/2N2K2 b - -,33,1048,31095,985254,28837503,912952597 -3qkbnr/2p1p1p1/rp3p2/p2pP2p/2P1bPPP/N2P3R/PP2K1B1/R1BQ2N1 b k -,30,1073,32358,1168064,36064555,1312472300 -rn1k1b2/NQ1q1b1r/1pp1p3/5Ppp/3PPP2/2p2N1P/PP2K3/1RBB1R2 b - -,34,1457,43583,1830664,56317289,2339990647 -5b2/8/2k3P1/1b6/5N2/1N6/1K3b2/6R1 w - -,31,770,20262,514598,13127146,335561171 -4n1r1/k5p1/2b5/3p3p/P2P4/b6B/K6Q/1R2n3 b - -,26,915,23541,833284,22591187,795973469 -6Q1/3k1n2/8/1P1P4/2RP3P/8/4K3/1N6 w - -,39,274,10361,67269,2461311,17822109 -k7/8/5P1N/7P/2pNb2K/2P1p3/1r3PR1/8 b - -,28,764,18656,488541,11315614,287252038 -1r3kn1/p1rp2p1/1p2b3/4NpP1/3q1P1p/2pQ4/Pb2P1BP/R1BK3R w - -,32,1307,40658,1633502,53687353,2136338738 -8/8/2P5/2K5/5k2/8/4n3/8 b - -,13,90,1158,8928,113154,925509 -8/q7/2P2P2/7k/p6p/8/1K6/8 b - -,23,174,4124,25254,607335,4467051 -2k2q2/2P3b1/1B2b3/1p1pP3/1pr2r2/7B/6Pn/4K3 w - -,15,598,8478,348811,5126989,214770074 -2kN1r2/2n5/2Q5/7p/7P/1K1RB3/8/8 w - -,53,630,30338,407444,18229535,265898430 -rn1qk1r1/p2Q4/b1p2ppp/1p6/1P2PpP1/1P4nP/P1KPN1BR/R1B5 b q -,4,112,3179,87724,2566073,71788761 -3k1b2/1R6/2P1r2n/3p1P2/8/6P1/2KNn3/8 w - -,29,733,17760,455252,10323987,267607704 -rnb1kbnr/p1p3pp/1p2pq2/3p1p2/PP4P1/5P1P/2PPP3/RNBQKBNR w KQkq -,21,851,19098,746156,17976207,688334021 -8/B1R5/5Q1P/8/1k1P4/8/1b6/1K6 w - -,41,350,13574,106223,4121774,36377434 -r4br1/2pkpp2/2nqb1p1/pp6/1PPp1n2/B2PPP1P/P2N2BR/1R1QK1N1 w - -,27,1077,28703,1178760,32550954,1360157303 -2k5/2P3b1/4P3/1p1pP3/1p6/5r2/8/3K1n1q w - -,5,176,853,28484,173557,5632567 -3n4/5k2/8/3r1n1R/2p5/2NB4/8/1K6 b - -,28,744,18284,484580,11704564,306512659 -3krb1r/2p1p3/4b3/pN3pP1/pqPp4/3P1P1P/PBK2R2/5BNR b - -,30,689,21396,492324,15609594,366972117 -N7/6nr/5P1k/1p2B3/2Pb2P1/1pRB4/P2q4/RK6 b - -,33,675,21517,500163,16647037,421355655 -1n5k/1b2p1r1/1B4p1/1P1p1p1p/2p2PPP/1p2P1K1/3bq1BN/1NR2R2 w - -,31,1074,27623,973657,25706709,918878902 -8/6b1/7r/Pk2p3/1n4Np/K1P1P3/1B6/1b6 b - -,33,377,10572,125127,3449824,41620286 -1n4rk/1bqpP2p/rp4p1/P5BP/3p1p2/5R2/P3PPP1/R2K1BN1 w - -,30,973,29645,993508,31661352,1081145900 -8/8/6k1/2P5/8/3K3p/7p/7R b - -,8,135,1102,20467,196274,3582896 -4k1n1/8/8/1K3P2/1P4p1/pN6/5r2/5N2 b - -,21,355,7339,116770,2409665,37987725 -8/2k5/1q5n/1QPP2r1/1KP1p2R/5Ppp/8/2R5 w - -,25,707,18469,489546,13982868,364753053 -8/2k5/1N4n1/8/3p4/8/8/K4N1r b - -,22,211,4228,49471,1078655,13841897 -R7/8/8/2p3RK/2P5/3q4/3N4/2k5 b - -,26,676,14550,364433,7744012,191362401 -5n2/7k/4p1p1/7p/1p5P/2b4r/2R5/5K1B w - -,20,468,9214,223628,4540694,111898080 -1q2R3/4k1p1/8/8/b5P1/N2K3n/8/8 b - -,7,137,4266,66477,2073667,32144267 -rn4r1/p2kp2p/2p5/rBb2p2/5B1P/8/1P3PPR/2K3R1 b - -,35,1038,33502,990667,32071943,945027465 -4n3/6b1/4r1pp/P1k1p3/4B1P1/2PPP2P/R3b3/B3KN2 b - -,21,574,12583,337049,7727643,205099292 -4r3/1k5b/8/p7/8/8/8/6K1 w - -,5,150,711,20013,102714,2844799 -8/5Pr1/7k/2P5/1p3bP1/8/2R2K2/1B6 b - -,20,374,6470,139935,2441328,58481903 -1rb1kbr1/pB1p4/4pn2/6p1/P2P2Pp/2p4P/2P1P3/RNBQK1NR w K -,29,810,23046,666515,19222668,567279167 -2r3nr/4kp1p/N3p1pb/7P/b1p1PqP1/B4P2/P2P1K1R/RQ6 b - -,6,236,8450,293895,10690348,374870675 -rnbqkbnr/1ppp4/4p1p1/p4p1p/1P2P3/5P2/P1PP1KPP/RNBQ1BNR w kq -,32,1082,32640,1107158,33509021,1149251355 -3k4/8/2K5/4P3/1N3R1P/2p2p2/4r3/8 b - -,16,345,4901,105615,1539542,33172663 -2b3k1/8/5PP1/7P/2p5/5K2/8/R7 b - -,10,202,1918,38487,375945,7437613 -r3kbnr/2qn2p1/8/pppBpp1P/3P1Pb1/P1P1P3/1P2Q2P/RNB1K1NR w KQkq -,43,1674,67202,2613497,100202988,3920538052 -3k4/8/2N2r1Q/Pp6/8/1p5K/1b2r3/8 b - -,5,116,3315,78127,2228902,53543807 -rn3bkr/1bqpp3/p7/2p2p1p/P2P4/2N1P1p1/1p2NPPP/R1K1QB1R w - -,5,198,5805,228659,6725857,263051707 -8/3r4/8/5k2/3B1P2/3N3p/8/3R1KR1 b - -,14,477,7276,238607,3754056,123548155 -6n1/1r6/3k1p1p/1B3PrP/P5R1/3P4/2NB1b1K/8 w - -,34,951,27846,742335,21081172,549200480 -2k5/8/8/2P2p1p/3N4/8/8/B6K b - -,7,98,675,11271,75186,1343756 -1R6/3k1p2/4r3/pr5p/1b2p3/p1P4B/5P1P/1RN2K2 w - -,30,638,19245,471008,14364612,372875315 -4q3/8/k3P3/3B4/1R4pb/K3Q3/6P1/8 w - -,47,994,39445,833232,31094669,677774682 -b7/b4N2/1k6/4r2P/P3p3/8/4K3/8 b - -,21,276,5782,67131,1468441,16375198 -1R4r1/8/1n5k/8/8/7K/2bp2B1/8 w - -,18,593,11562,359830,7250821,222183429 -1B6/3n1k2/r7/5P1P/2K2n2/4Bp2/8/8 w - -,21,694,13619,400761,7900947,217328371 -2b1n3/N1b1k3/pp3n1p/3p1P2/P1Bppp2/1PP4P/5K2/R3B1NR w - -,25,642,16049,405918,10643622,268539776 -1N6/4p3/3Q1P1k/p1K4P/2n5/1r5p/4R3/3b3n b - -,33,1141,32956,1055956,30047945,940232324 -6nr/2k4r/2n5/Pp1p3p/Rp1PPqPP/1P3N2/8/2N1K2R b - -,40,881,34838,753409,29371081,644758039 -2Rr4/p4k2/1N6/n1n5/pP1p1K1b/5p2/5P2/B5n1 w - -,20,690,12969,405402,7942047,238035140 -8/1rB2Bk1/1b6/P7/1p2K2p/7N/R7/8 b - -,18,651,11768,399315,7633215,246839494 -1nq2bnr/3k3p/bp2p1p1/r1p2p2/P1p1N1P1/BQ2KP1P/3PP1B1/3R2NR w - -,36,1040,35126,1057110,35499952,1114329327 -r1b3nr/3pqp2/4Nk1b/pppP2pp/QnP5/P4PP1/3RP2P/4KBNR w K -,34,995,30995,941711,29519042,917534975 -1n4R1/B6k/bP6/4p3/2pP1P1P/5pr1/3n1K2/4R3 w - -,31,640,16319,352129,8616058,192441168 -r7/n3b1kr/b5p1/pP1PNp2/PP1p1P1p/4P2Q/5KPn/R1B3R1 b - -,35,1132,38554,1277983,43129223,1459275036 -Rn6/P3k3/8/8/3NK3/1p5P/8/6R1 w - -,35,336,11490,85158,2797520,24142186 -8/r3b1kB/8/7n/3p3r/2p5/1n2K1b1/7R w - -,19,886,14681,661139,10977316,485630411 -2b1kb2/r3p1rp/2p3pn/P2P4/2PBP3/N5P1/p4P1P/R1N1KB1R w KQ -,36,968,34825,920124,32970456,890776319 -1kr5/n2r3P/p4B2/P7/1P2B2P/1Pp5/8/2N3K1 w - -,34,843,24656,583560,16482259,395833016 -6n1/6k1/8/8/7N/8/8/N2K4 b - -,9,99,839,10980,109156,1498575 -8/8/2b2b2/4k1P1/2P5/Np4p1/1N6/3R1K2 w - -,22,415,8441,159366,3269966,63248038 -rnbqkbnr/ppppppp1/7p/8/7P/7N/PPPPPPP1/RNBQKB1R b KQkq -,19,418,8955,213604,5117449,132503535 -1r3bn1/5k1r/3p1p1p/pp5P/P5P1/2p2P2/1R1P2B1/1NB2RK1 w - -,21,446,10574,230677,5908173,131590584 -r1b1k2r/pp1p1p1p/1qnP4/2pnpPp1/6P1/1QN4P/PP1BP3/R3KBNR b KQkq -,33,1111,35600,1224307,38483591,1335232912 -5Nq1/3Bk3/3p4/3P1Pb1/4p1nR/8/8/2n2K1n b - -,31,585,16727,326121,9654555,189188785 -R7/3bNk2/8/1P2pr2/pb3P1P/2n5/2KB4/5R2 w - -,36,982,33968,956619,31851086,910469712 -1rb1q3/p2pn1p1/P1p1R3/1pP2P1k/P2P3p/B3b2P/2R1K3/1NQ5 w - -,36,1054,38314,1095017,38984367,1114866072 -Q7/b4k2/p3n3/P2Pp3/P1p5/2N2K2/8/4RB2 b - -,20,619,10789,346320,5819642,192660918 -6r1/4kn2/5n2/1BN5/8/8/1K6/8 w - -,25,755,16284,453756,9073957,241513934 -3K1R2/8/2q1b3/P7/8/8/8/7k w - -,12,337,3803,111433,1396120,39887797 -1nb2knr/7p/p2N4/p1pP4/P1Pb2p1/R3PP2/2r2NBP/q1B1K1R1 w - -,31,1091,28554,1022724,26707435,972190473 -7k/8/8/1p6/1n2b3/8/7n/4K3 w - -,4,100,468,10709,45652,1026956 -rnb1qbkr/2ppp3/p7/5ppp/P1pP1N2/4P3/NPK2PPP/RQn2B1R b - -,28,801,23308,681754,20827492,630470805 -4B2k/8/n2BP1R1/1p3P1K/8/8/8/8 b - -,6,175,1053,30524,210183,5835316 -r2k1b1r/4pP1p/pn1q2p1/1p2p1P1/1PP2P2/P2p2RB/3K2NP/RNB5 w - -,24,697,17339,512043,13636590,411450423 -3R4/1B5k/7P/5b2/4n2K/5b2/8/8 b - -,22,456,9965,200833,4407057,90958388 -1r6/3k4/1p3R2/1P3pNK/P7/3Bp3/8/b7 w - -,26,480,11823,224040,5520669,109197253 -1n4nr/p1kq3r/Qb6/P2p3p/Rp1PPP1P/1P4PR/3N4/2N2K2 b - -,30,855,22432,672552,18947471,584233130 -5k2/2R5/1p2B2N/1P6/P7/8/5K1b/b2r4 b - -,27,750,19478,508444,13283045,337913095 -4q3/R7/8/2p3RK/2P5/8/3N4/2k5 w - -,5,122,3201,66985,1686922,35109654 -b7/3q4/R5Bk/1P6/p4P1p/8/8/1K6 w - -,24,544,10822,254566,4863876,122903736 -6k1/8/B1n4p/Pp1p3P/P2pPp1B/5R1N/b2K1PP1/R6q w - -,34,925,28237,730569,21965299,556628790 -5Qk1/p7/P7/1p1p4/3P3p/7P/3qN2K/B7 b - -,2,31,498,9867,167672,3453570 -8/7p/2R4P/3K2kP/5r1n/2p2p2/8/8 w - -,15,262,3575,65627,951922,18766833 -rnbqk2r/ppppn2p/6pB/2b1pp2/1PP4P/3PR3/P3PPP1/RN1QKBN1 b Qkq -,23,660,16609,494313,13401921,411362182 -2k5/4b1P1/8/4Nq1n/8/8/7K/8 b - -,36,470,15133,189922,6075778,77102172 -8/1pp5/3R2P1/1pkn1p1p/5P2/r6b/8/1N2K1N1 b - -,32,587,15403,291640,7270851,142111868 -r7/2b3r1/1N2P3/2p5/P2kb2P/4p3/1p1PR3/3K4 b - -,50,734,32641,522561,22121775,377053578 -7k/2n5/1p6/8/8/8/1Kb4n/8 w - -,6,123,488,9720,49294,1001162 -5B2/2k5/P6P/4P3/b1K3P1/8/8/8 b - -,13,190,2193,33373,390197,6258797 -2bq1b2/2pkp3/nr1p1n1p/3P1pp1/ppP3P1/PPBQP2P/3N1P2/1R2KBNR w K -,32,832,28170,725952,25411630,670418870 -8/5n2/3p4/5kN1/8/3K4/8/7B b - -,12,212,2201,39194,403566,7095529 -r3kbn1/pB5r/1P3p1p/2p1p3/P1P4P/2R2N2/8/2B1K1NR b - -,24,826,18750,657090,14839015,528756403 -r1b1k3/3qbppr/n1p1p2n/1p1p3N/Pp5P/2PP1P1B/4P3/RNBQK2R b KQ -,34,1246,42036,1522016,53058587,1926294372 -2N4k/5r2/N2p1q2/1p3n2/P1P3Pp/1P1P1P2/3BQ1BP/2K1R2R b - -,34,1335,44121,1778048,57864342,2380525349 -r3kbnr/p3p3/bqnp1p2/1pp4p/1P3p1P/P1PP1N2/3KPPP1/RNQ2B1R w kq -,25,789,20061,630780,16454035,524512877 -q4bn1/2p1pkpb/rp3P1r/p2P3p/5PPP/NQ1P3R/PP4B1/R1BK2N1 w - -,36,1046,39636,1142821,44549256,1322711936 -1n2K3/8/4b3/1kp5/8/8/8/B5q1 b - -,40,353,13695,145769,5490802,58132643 -3k2br/2p3r1/3N4/p4pb1/p1Pp3R/P1BP1P2/6q1/3K2N1 w - -,30,1200,28217,1113783,25466144,999872808 -r1b3n1/ppp4r/2kp1pQb/3q2pp/4PpnP/NPP2PPR/P3K3/2R2BN1 b - -,40,1057,39826,1125940,41946032,1242778472 -8/rk6/5pP1/p1pP4/PNP4q/1P3p2/8/1RBK3R w - -,24,614,14703,376826,9301478,242989419 -2k5/b3n3/5P2/2Nb4/3p1bP1/3K2pP/8/1B6 w - -,16,524,7752,228853,3558624,99594791 -r4b2/1b1npk1r/p2p4/P1p4p/3q4/4P1PN/3Q1PP1/RK1N1B1R b - -,49,1442,60789,1870035,75038000,2401164091 -rnbq1bn1/pppppkp1/5p1r/7p/PP6/2P2N2/1B1PPPPP/RN1QKB1R b KQ -,23,575,12578,335143,7917062,223760273 -2bq1bn1/1ppp1p1r/r2kp1p1/p6p/1nP5/P2P1P2/R1QNP1PP/4KBNR b K -,37,886,29592,745446,24232990,635189989 -8/6r1/p2k1P1p/P2pR2P/1b6/1b1p2P1/3R4/5K2 w - -,26,666,15795,395549,9081346,226660397 -rnbqkb1r/pppp1ppp/8/4p3/P2PPB2/4n3/1PP1QPPP/RN2KBNR b KQkq -,37,1236,44982,1592016,57305859,2102299493 -3qkbnr/1rp4b/p1np1p1p/1p2p3/1P5p/P1N2PP1/3PK1BR/R1B2QN1 w k -,29,946,27124,876111,26412955,858095401 -8/1B3n1n/8/P2p1P1p/1p6/1k5P/2R2R1b/2K3N1 b - -,20,575,10149,298732,5436025,162478003 -3k1b2/pn4r1/1P2B3/P1p1p1pP/2P5/R4R2/6N1/4K3 w - -,39,623,23082,399215,14293335,257076075 -8/6p1/3R4/8/2K3n1/6k1/7q/3b4 w - -,21,643,10178,318116,4804326,152424344 -4kr1r/2pR3p/1B3p1n/Q4n2/PP3bP1/2pq4/4PR1P/4K3 b - -,43,1329,47488,1478137,50546425,1594790336 -5Q2/2kb1r2/p7/1ppKP2p/R4pPP/1PPR4/4N3/1N6 b - -,20,773,14318,518222,9724714,340555056 -8/8/2P5/K7/5k2/6n1/8/8 w - -,6,78,593,7647,65066,807587 -1n3B1r/5b1k/1p3pRP/1P1p1N2/1p1p4/5B2/6K1/6r1 w - -,4,84,2298,48990,1273773,28981276 -r4bnr/1Bqnk1p1/8/ppp1pp1P/3P1Pb1/P1P1P3/1P3Q1P/RNB1K1NR b KQ -,41,1450,57711,2016071,80287095,2782731786 -8/8/4n2k/1B5p/7p/3pP3/8/bR4K1 w - -,21,424,9687,186714,4244434,82317630 -1rbkr3/p1p1p2p/Qpqn3b/1B1pP1p1/1PPn1pP1/3P1P2/PN1B3P/2R1K1NR w - -,32,1096,34148,1157201,37012981,1251589316 -r6B/pRb1k3/P1P5/2Pr4/B1N5/5KP1/1P5P/2q5 b - -,40,1029,39168,971092,36676679,898659156 -4n3/8/P1p5/5kp1/5r2/1PB3N1/2N1K2R/b7 b - -,3,114,2633,86862,2006577,64096322 -3b4/k7/8/8/8/3K1Q1Q/6P1/5B2 b - -,10,396,3770,157237,1502956,64586643 -n2k4/8/5nR1/1P1P4/3P3P/2p4r/5K1B/1N4Q1 w - -,33,636,19298,366322,11805273,230924863 -r1bnk1r1/p1p2ppp/7n/1p4q1/Pb1pp1PP/BPN2P1R/2PPPK2/RQ3BN1 b q -,49,1329,61475,1710636,75644036,2155923454 -8/8/1k4pr/p3p2p/PB2R2P/3p1P2/6KR/8 w - -,26,255,6757,81504,2167742,30245736 -r2qkbnr/ppp4p/3p1p2/4p1p1/Pn4b1/RPP3PN/3PPP1P/1NBQKB1R b Kkq -,39,672,25655,540869,20131579,481608338 -3r4/2p5/1p5N/1p2np2/5P1K/2k5/8/8 w - -,9,289,2544,72169,685308,17922249 -4k3/4r2p/2b4P/3p4/p1p2b2/1B4p1/3BR2r/3K4 b - -,35,732,24615,506835,17136659,346915189 -r7/P1pr2Pn/4k2p/P2p3P/3Pp3/1P1nK2R/1B3R2/1B1b4 w - -,31,959,29916,912833,28943315,869820309 -2k3n1/8/8/7N/8/5N2/4K3/8 w - -,19,150,2707,26347,461245,4704168 -1n1b4/2k1PnK1/8/2p5/2Pp4/8/8/5b2 w - -,14,244,2988,56382,708720,14257804 -7k/3b4/1p3n1P/1P1pR1Kb/8/5B2/8/8 b - -,21,405,7816,153768,2903360,58679040 -4n3/Nbb1k3/pp3n1p/3ppP2/P2p1p2/1PP4P/4BK2/R3B1NR b - -,26,675,16211,427687,10214867,276894943 -2k4q/2P3b1/4b3/1p1pP3/1p3r2/4r3/4B1P1/4Kn2 b - -,50,231,10830,89503,4053167,42110869 -1R6/r3P3/2b2kp1/pp1p1p2/Pbq2P2/6P1/2pB2P1/R2KN3 w - -,2,67,1748,55044,1395976,44520981 -r1bqkbnr/pppp1p1p/2n1p1p1/8/1P2P3/3B4/P1PP1PPP/RNBQK1NR w KQkq -,30,987,30343,986600,30790429,1010218060 -6k1/8/1R1b4/8/3p2b1/6p1/1B4P1/2K5 w - -,15,327,5913,119075,2291731,43958753 -8/7k/2b4P/P3P3/2K3P1/4p1B1/8/8 w - -,14,223,3149,44398,647296,8836899 -4k3/8/8/2K1P3/1N3R1P/2p2p2/8/7r b - -,15,355,5317,122540,1888515,42483287 -R7/4kqp1/8/5K2/b3pP2/N5Pn/8/8 w - -,3,89,1324,36981,587049,16735774 -3RQ3/7k/p7/P7/N7/7B/4p3/4K3 w - -,39,87,3386,13589,545524,2810179 -3r4/k3N3/5r2/1P6/6p1/2K5/8/6n1 b - -,36,410,10880,130245,3590156,41349250 -3b4/1r4k1/3r2p1/p3p2p/P3PP1P/1R2N3/3QK2R/6N1 b - -,35,1469,45664,1886417,55357694,2257221955 -r4bk1/1p1bp1Bp/3p3n/2R3p1/2P1pP2/6PN/3K3P/5B1R b - -,35,1112,35368,1076552,32258398,969923861 -B5r1/4k2b/n7/7K/8/2Bp4/8/R2r4 w - -,27,908,23777,758115,20095163,633277520 -k7/Pq5p/2nB4/3p4/8/1b1p4/6K1/5nN1 w - -,19,635,10446,351979,5508215,188788974 -4k1r1/3n4/1Bb1n3/1p1r2p1/p1p2P1p/b3p1P1/2KN1N2/R4BR1 w - -,38,1685,59818,2593114,90952924,3907996440 -Rr6/1k2b3/5r2/p4p2/4p2p/R1P5/4NP1P/4KB2 b - -,31,683,19362,485717,13835284,370066219 -rnbqkb1r/2ppp1pp/1p6/5p2/1PBPP1n1/p4N2/P1PN1PPP/1RBQK2R w Kk -,35,947,32995,917880,32215254,926813913 -rn4k1/2q5/1p1Bp3/pp1p1pp1/P4P2/3QKb2/2N5/6N1 b - -,37,1146,39554,1203798,39635355,1202073820 -2r5/8/p3Pn2/P1kP1B1b/7p/2p4N/6P1/1K1N2R1 w - -,24,707,17080,472154,11908796,315602598 -rnbqkb1r/2ppp1pp/1p5n/p4p2/P2P4/1P3N2/2PNPPPP/R1BQKB1R b KQkq -,21,484,11182,290752,7317300,207317100 -4k3/8/8/4n3/8/3p4/6N1/1K3N1r w - -,8,172,1882,42592,519514,11913038 -2rk2nr/pbp2p1p/4p1pb/1p1p4/4PqPP/N2B1P2/P2P1K1R/RQB5 b - -,36,830,30525,793217,29223297,826616213 -bn3R1r/3k3p/2p5/p1Pp4/P7/3p4/3P3n/1NB2qnK w - -,18,464,6528,183045,2737019,80665301 -4b3/4k3/1b2P3/1P6/7P/p5n1/8/KR6 b - -,27,300,7721,102211,2515350,35549130 -r1b5/1pp2nr1/pk1p1p2/4P1bp/1P3p1P/N2K1PPR/P1n1N3/5B2 b - -,32,671,21367,463014,15121170,338650402 -8/8/2K2k2/3r1P2/7p/p7/8/2R3b1 w - -,13,322,4519,106148,1565395,36661875 -1r3br1/2nkp1pp/7n/ppp2pQ1/7P/2Pp1R1K/PB1N4/RN3B2 b - -,27,941,22472,790926,18806926,675153743 -N7/4B1nr/1p5k/5P1q/2P3p1/pp1B1N1P/P2R3b/RK6 w - -,35,787,25922,658683,21413787,599048081 -2k4b/P1P5/2N1p1p1/3P2rp/R6P/3b2B1/2n2R2/3K4 b - -,29,1152,29985,1112932,28731092,1027187312 -4N3/4n3/4P1P1/P7/3K4/7p/2b3k1/8 b - -,22,237,4983,58748,1189678,14760384 -2B3k1/5b2/2n4r/pP3pp1/P4PP1/2R1PRK1/8/2b5 b - -,36,766,25565,583848,18553374,445641172 -1r1q1b1r/2n3k1/p2p2bp/P1p2p1R/3P1p2/P1K3p1/2Q3B1/R1B3N1 w - -,43,1539,59390,2113395,81039211,2875343546 -1r1k1b1N/pR1b2rp/2pp4/2n1pP1p/1p1P1P1P/6PR/2P1BB2/1K6 b - -,33,1134,34560,1142726,34872907,1131968575 -1r6/p1p3pP/2r1P1k1/P1n3P1/2Rb4/1P1b2N1/3K1N2/8 w - -,29,1124,30265,1114960,30332340,1079839396 -5r2/k7/8/1P3N2/6p1/2Kr4/8/6n1 w - -,5,146,1846,52164,578940,15992114 -8/8/8/2N5/3k4/rP3P1p/4K2P/8 w - -,14,148,1822,25780,299909,4500192 -R7/8/8/2p4K/2P5/5N2/2q3R1/2k5 w - -,38,699,20272,377965,10555387,202466971 -5rn1/p1nbk3/q2p3P/2p1pp2/pPP2pPp/Q2P3R/2KNPP2/R4B2 w - -,36,1309,45420,1619451,56095614,2002461783 -rnbqkbnr/1p2pp1p/3p4/p5p1/PPp2PP1/3P4/R1P1P2P/1NBQKBNR b Kkq -,30,839,25861,729818,23178449,672681117 -rnbqkbnr/ppp1pppp/8/3p4/5P2/8/PPPPP1PP/RNBQKBNR b KQkq -,28,557,16262,359553,10932394,265969132 -8/8/1k2N3/1p2P3/1p1p2B1/3K1r2/3n4/7q w - -,5,184,2372,84596,1195641,40794846 -1r5N/1n1bkP1p/B2b4/p2pp1r1/2pP1PpP/2p3R1/2K4B/8 w - -,27,842,21386,654993,16822725,510658281 -1k3b2/4Q3/8/2p3NP/2bp4/P1P2KP1/2N2P2/1r5R w - -,46,1170,47460,1148562,44377163,1055713890 -rN2k3/5N2/3P4/pp6/4B2p/P3K2P/1P1BP3/R5r1 b - -,21,813,14421,527748,9440843,333893820 -rnb2br1/pp3n1p/4pk2/5pp1/P1P2BPP/2P1N2N/4PP2/R2QKB1R w K -,38,1030,40488,1093528,43681164,1186402311 -8/8/1K1k4/7P/5N2/3r4/5p2/6b1 b - -,19,203,4421,48436,1145349,11859158 -8/2B2B1k/4PR2/1p3P1K/8/8/8/2n5 b - -,7,128,941,18017,136754,2865827 -1r1k4/6r1/p2qpnp1/2p4p/P3PB1P/1P3P1B/R2PK3/2B1R3 b - -,43,1284,51376,1540425,59011020,1788314412 -rnbqkb1r/2pppppp/1p5n/8/p1BPP3/5N2/PPPN1PPP/1RBQK2R w Kk -,32,709,22998,558141,18561781,486238566 -1rb1r3/2Np3k/8/p4p2/P1P2PPp/1P1n3P/2QK4/R1N3n1 w - -,25,896,22459,735411,19322096,610038092 -3k2nr/p2B3r/n5Q1/Pqbp3p/1p1PP2P/1P3PP1/R3N3/1N3K1R b - -,29,1260,33782,1415607,39355007,1611854060 -8/4k2b/2B1P2N/Pp3P1K/6PR/n7/1r4b1/4B3 w - -,23,529,12203,286212,6907718,164389046 -rnbqkb1r/pppppp1p/5n2/6p1/5B2/3P2P1/PPP1PP1P/RN1QKBNR w KQkq -,30,710,21645,547191,16950977,454275243 -8/8/P7/2p5/PkP2p2/5N2/6K1/3R4 w - -,30,177,4535,23240,553695,3131814 -8/1K6/8/8/3k4/3p4/8/6n1 w - -,8,85,461,5444,33331,428452 -rnbqkb1r/pp1pp2p/2p5/7n/P7/1QPp3P/1P1PN1pR/RNB1K3 b Q -,26,641,17860,447638,13447951,349747211 -rnbqkbnr/pp2p1p1/8/3p1p1p/PpP5/7N/1B1PPPPP/RN1QKB1R w KQkq -,29,840,25175,776716,24252616,782985729 -2b2b1r/r1pk3p/p5Q1/np2p1PP/2Pp4/PN3K2/RP6/5BN1 b - -,25,898,18443,625638,13707047,450309618 -5k2/p1R3p1/1p5q/5pn1/P1N1PP1p/1b5B/1b3K1P/2q4R b - -,45,1147,49947,1325374,57935240,1554266886 -2k5/8/8/p2br3/8/8/8/6K1 b - -,29,95,2721,9987,277832,1266318 -r1n3r1/3k1p2/2p2P2/1P2b3/p2p3p/P1P1p3/NB2P3/2R1K2B b - -,36,580,18325,329478,10181569,195099777 -2R4r/1k6/1p2R3/pP2pp2/8/b5K1/PN6/1n1B4 b - -,25,779,17121,512568,11415602,336779269 -3q4/8/2P4k/8/8/K5Qp/8/8 w - -,28,520,10977,212711,4358760,87793150 -r2n3r/1bp1k1pp/1N4P1/pP3p2/1b1pp1nP/BP1P1PqR/2P1P1B1/1Q2RKN1 b - -,49,1242,55490,1445881,64846110,1747657317 -rRbb4/6kr/3pP3/1P2N2P/p3nP1P/p1N5/8/1KB4R b - -,33,1054,32015,1049715,31109451,1035552484 -1r1q1b1r/2n3kb/p2p3p/P1p1pp1R/3P1P2/PQK3p1/6B1/R1B3N1 b - -,31,1289,39235,1583516,49467352,1947322385 -1R6/Q4k2/6p1/pp1p1p2/P4P2/3KBqP1/6P1/R3b3 b - -,2,68,1143,33972,601517,19615250 -2k5/8/6n1/7N/8/3K1N2/8/8 b - -,11,196,2130,37679,418011,7275358 -3N4/3b4/3p1P2/8/5kn1/6R1/K7/2q5 b - -,37,513,15932,243503,7654917,123421584 -2k5/2P1qrb1/3N3r/1p1ppb2/Bp1P2n1/8/6PR/5KB1 b - -,4,82,3432,67484,2774078,59747507 -r5rk/1p6/n7/3pp1pq/PB6/1p4PK/6NP/RN4b1 w - -,1,43,699,29691,518142,21779716 -7k/8/5PP1/7P/2p5/7K/8/3R3b b - -,9,169,1712,30745,304830,5516526 -1Nk3nQ/7p/4Pppb/7P/2p1PqP1/5P2/b2r4/1RB1K2R b - -,36,879,30855,835835,28891064,840258391 -4k3/5R2/2rR4/B4P2/8/7p/N7/5K2 b - -,12,386,4813,144838,1887406,55407339 -kn6/8/6N1/2P5/2B5/1p6/8/1K6 w - -,20,112,2075,16276,293698,2526186 -1rbq1rk1/np2ppb1/1p3np1/2p4p/P1Pp1N1P/3PBPP1/RP1NB3/3K3R b - -,29,819,24869,724536,22872155,678797034 -1N1k4/6b1/P3p1p1/1bPPr2p/3B2RP/8/3K3R/n4r2 w - -,26,986,24316,870896,22161479,764575142 -1n1qkb1r/3bp1pp/rppp4/p5NP/P1PP1pn1/1P2PN2/4QPP1/R1B1KB1R w KQk -,35,783,28265,688515,25180829,655133174 -3knr2/8/7n/7B/K7/8/8/8 w - -,12,239,2953,61791,783356,17413679 -1rbqkbnr/pp1ppp1p/n1p3p1/8/3PPPP1/P7/1PPQ3P/RNB1KBNR w KQk -,35,801,27711,705986,24523200,674315687 -5b2/7r/2k4p/Bn3p1P/P4N2/3P1K2/8/5R2 w - -,28,647,17738,395374,10806715,243795848 -8/1R6/rn1b4/Pk2p2p/3P3p/2PbP3/1K6/BB3N2 w - -,23,565,12698,327247,7504855,197773383 -r1b1kb1r/p4ppp/3p1n2/1pp3P1/P2p1q2/R7/1PK1P2P/1NBQ1BNR b kq -,43,1257,52002,1536287,62485545,1903995725 -7n/1B6/3p4/4k1N1/8/3K4/8/2q5 w - -,16,376,4551,106690,1400183,33316154 -8/r3n2k/2Q1p3/p2N1p2/Pp1N1Pp1/7b/5K2/8 w - -,35,673,21785,419996,13076486,260099910 -8/6k1/n7/rb3pP1/1p1p3p/1P4nP/1K6/8 w - -,4,112,518,14810,68686,1980260 -1k5r/n7/p4B2/P7/1P2B2P/1Ppr4/7K/2N5 w - -,27,641,15406,372599,8878345,219512606 -7k/5b2/1P6/p4BP1/P3Pp2/1R3R1r/3nK3/2b5 b - -,26,690,18199,455545,12265893,305432538 -n7/3k4/8/1P1P2n1/3P3P/2p1K1R1/Q6r/1N6 w - -,31,692,19782,411462,11714711,238179844 -rR6/2b3k1/3pb3/1P1NN2r/p4P1P/2n5/2K5/2B4R w - -,40,1346,50280,1678048,60380649,1985600177 -7k/3n1b2/1p5P/1P1p2B1/4r2R/3p2K1/2b3B1/8 b - -,32,768,21493,516052,13914575,337775486 -rnb2b1r/3p3k/1p3p2/pP1p3P/3p3N/2P2B2/5BK1/1R3R2 w - -,32,678,21780,480500,16036312,369051004 -rnb1kbnr/pp2p1pp/3q4/2p2P2/N1Pp1P2/PP1P3P/4PK2/R1BQ1BNR b kq -,34,799,26094,664056,21467579,578883012 -6B1/k7/8/6b1/8/1K4p1/5r2/8 w - -,10,286,3425,90249,1131734,28978945 -r1b1kb1r/pp1pp1pp/n4p1n/2p5/4PP2/2PP3P/Pq2B1P1/RNBQK1NR w KQkq -,26,836,21609,682795,18829161,596690993 -3k4/8/8/2PP2R1/2K1p3/5Pp1/5rp1/8 w - -,17,286,4720,84434,1384633,26187233 -rnb3nr/2p1p3/p3k3/1pPp1pq1/4P1Q1/N6P/PP1b1PP1/R1B1KBNR w KQ -,3,108,3572,118738,4095070,134943828 -2b5/8/4nr1k/P2p1p2/1p3PPp/1P2R2P/3n4/3K4 w - -,17,395,6211,153620,2356984,59596908 -1rbqkbnr/p1Q1p1p1/n2p1p2/1p4Np/7P/3P2P1/PPP1PP2/RNB1KB1R w KQ -,45,1013,43686,1079349,44985842,1194756513 -k7/5n1p/P1b1q3/3p1N2/8/3p3K/5B2/5n2 w - -,13,441,6104,211282,3135450,109077982 -r2qkb1r/1bppp2p/1p3np1/p4p2/P1PnP3/3B1P2/1P1B2PP/RN1QK1NR w KQkq -,33,1287,41535,1586816,52624933,1989735298 -5k1r/1n6/8/7n/2B5/2N5/6R1/1K6 w - -,37,470,15872,276983,8634407,171968305 -8/7p/2bb2kP/p2pr2r/B1p2P2/2p3p1/2R2B2/3K4 w - -,20,673,13795,456739,9578614,312493879 -2r3nr/pbp1kp1p/4p1pb/1N1p4/4PqPP/3B1P2/P2P1K1R/RQB5 w - -,30,1109,32317,1190580,37136260,1361377402 -r1bqkbnr/p3pp2/1pp5/1n3Ppp/4p3/2P4P/PP1N1KPR/R1BQ1BN1 w kq -,34,1153,36802,1281678,41485383,1475593848 -5R2/6bk/3Q4/4P2p/PN2P2P/3N4/6K1/8 b - -,5,230,1760,80448,649727,29017253 -B7/3k4/7B/p3P1P1/1p1K1R2/P6p/1P6/8 b - -,10,297,2420,72731,588854,17680403 -1kb2b2/8/3p1n1b/3P1Pp1/p1P1B1Pp/4K2P/2R2N2/4N1R1 b - -,21,517,9926,255650,4902072,129830088 -5knr/7p/p7/pNpPn3/P5P1/2rRb3/1q3N1P/2B1KBR1 w - -,29,1255,30325,1238723,31361858,1236215155 -8/1r6/r7/k7/N2P4/P4K2/R7/8 w - -,21,510,9843,228141,4450929,105497528 -1nb4k/2qppp1r/6p1/1PpBb2p/5PPP/Bp1PP3/8/RN1K2NR w - -,33,1016,33636,1068730,35919461,1167022171 -1rb1qbn1/ppppp1p1/5rk1/P7/P1P2PPp/B6P/R2P3N/1NQ2KR1 b - -,24,647,15455,465194,11816675,380467287 -8/6kN/8/2q5/Pp1rp1P1/2RP1N2/3Kp3/1r6 b - -,47,851,36652,670900,27100645,506328039 -3k4/1B5P/7B/4P1P1/1K6/8/8/1b6 w - -,25,258,6000,69236,1562031,18188537 -r2k1b1r/1p2pP1p/p2q2p1/4p1P1/nP1p1PR1/P1P4B/3K3P/RNB1N3 w - -,21,682,15682,504221,12482398,401531186 -8/p2q4/P6B/3Pk3/N6p/1K6/8/8 b - -,25,382,8352,130640,2842834,44281565 -1q2R3/6p1/5k2/8/b5P1/3K4/2N2n2/8 w - -,6,210,3906,123973,2193417,69345084 -8/1B2k2b/1p2P2N/P4P1K/6PR/n7/2r3b1/4B3 b - -,33,715,20024,460079,12488408,303921806 -rn3b1r/p1p1p2p/B1k4n/5pN1/8/8/PPpP1PPP/R1B2K1R b - -,15,427,7788,217032,4548523,125772830 -8/n2k4/p2p4/P2Pb1Q1/2p5/P3K2N/2BB3R/8 b - -,17,626,8723,333713,4695192,182987428 -8/8/P7/k1p3N1/P1P1R3/5p2/7K/8 w - -,21,104,2279,13384,281210,2026647 -1r4r1/p1p2kpp/n3b3/P3PNb1/4P3/2P3P1/1P3P1q/R3K1N1 w - -,25,1190,26884,1251801,27236046,1247486019 -rnb2br1/pp3k1p/4p1pn/5p2/P1p2B1P/2PPN2N/4PPP1/1R1QKB1R w K -,37,842,32028,788779,30262200,789055299 -Q4N2/8/7k/8/1p5K/3B2rp/8/8 w - -,34,437,13155,178705,5380957,74125731 -5R2/8/4k2p/rp5r/6p1/n3K3/8/8 b - -,23,402,9453,147999,3687591,55240699 -1n3bnr/7p/8/pppr2kb/3pP1Pq/1Q1P4/P1PK3B/RNR5 w - -,31,957,27112,877889,24750306,827421207 -rnbqkb1r/1ppppp1p/6pn/p7/4P1P1/7N/PPPP1P1P/RNBQKB1R w KQkq -,27,562,16189,381806,11516335,298534994 -3K4/2R5/4b3/P7/8/8/8/7k b - -,14,241,2711,45994,533276,9104744 -b7/8/1k5r/8/5Kp1/8/7p/8 w - -,6,178,764,22699,111448,3369547 -rnkq4/p6r/b1p3pp/1p3p2/1P2P1P1/1PK2pnP/P2PNR2/R1B2B2 b - -,41,787,29286,625174,22184710,505603334 -r1b2b1r/pp3k1p/2n1p1pn/5p2/P1p2B1P/2PPN3/4PPP1/1R1QKBNR b K -,30,1094,31975,1188154,35100630,1317993835 -rnb2r2/5k1p/1p2p3/p1P1n1b1/P3pP1p/2P5/1Q2P1NB/3RKB1R b - -,36,1171,40849,1280402,43990384,1381760087 -1n2kb1r/q3p1p1/rp1p4/B1p3Np/b1PP1pn1/RP2PNPB/4KP2/7R w k -,41,1298,51825,1641968,64193614,2069414179 -r1bqkb1r/p1pp1p1p/2n4n/1p2p1p1/3P4/3Q2P1/PPP1PP1P/RNB1KBNR w KQkq -,41,1266,48284,1508602,56333154,1793082683 -1n1bk3/r1Q2N2/b2P3p/RP3P2/1P6/2Rp1PK1/4q1B1/7q b - -,43,1253,47888,1457248,56622952,1760586838 -r3kbnr/p1p2p1p/b3p1p1/1p1p4/4PqPP/N2B1P2/P1QPK3/R1BR4 b kq -,43,1047,40566,1092681,41252950,1184083284 -8/4R3/6R1/2p3K1/2P5/4qN2/8/3k4 w - -,6,112,2955,52211,1384178,26477329 -6nr/2pbp2B/nr5k/1B2P3/1b4pP/6P1/q4P1K/1R4NR w - -,28,1251,35692,1536493,44721962,1903705125 -3rk3/1q1b2b1/7r/1p1pp3/BpP3np/3PB3/4N1P1/5KR1 w - -,26,1073,24664,1023884,23347785,979629984 -2b2bn1/1k4b1/3p4/3P1Pp1/p1P3Pp/4K2P/4RN2/1B2N1R1 b - -,22,549,12382,317430,7313495,192964113 -r1bk1b1r/pp1nqpnp/2ppp1p1/6N1/1P1P2P1/B1N1Q3/P1P1PK1P/R4B1R w - -,40,1004,39418,1045184,40967651,1135487384 -rnbqkb1r/pppp1p1p/4pn2/6p1/5B2/NP1P2P1/P1P1PP1P/R2QKBNR b KQkq -,30,860,25864,759541,23106494,695537139 -8/8/8/4k3/1K1p4/5n2/8/8 w - -,7,95,540,7439,45078,611327 -1r2rbk1/np2p3/1p3pp1/1qpn3p/PP5P/3P1PPb/1R2B3/3KR3 w - -,18,697,12522,481141,9388288,361353278 -8/2k5/P5r1/1p6/8/1p4N1/2r4b/7K b - -,34,201,7217,52272,1767219,14459701 -8/4k3/n7/7P/3PK3/8/2N5/8 w - -,14,160,2020,20954,269215,2809281 -3rkb2/p1Q1p2R/n1n5/3b4/pP1p4/3N1p2/5Pp1/BR4K1 w - -,42,960,38871,963272,38082848,989228336 -rnk1Q1r1/1b1p2b1/1P6/p3p1p1/1PPpPP2/7p/3N2PP/1RB1KB1R b - -,1,22,604,14247,392928,9838498 -r2n1r2/4k2p/1p6/5pp1/P5P1/7P/1R1Kb3/1r6 w - -,14,583,8830,352301,5464942,213224084 -8/2k5/7n/1qPP2r1/2P1p2R/K4Ppp/8/6R1 b - -,36,633,21212,389992,12702469,244172667 -8/3pBRk1/B1n4p/Pp5P/P2pPp2/5R2/b2K1PP1/R4qN1 b - -,4,145,4299,129906,3700678,111533172 -5kB1/P4r2/P7/1P6/3N3P/8/6K1/6B1 w - -,22,305,7721,107433,2847908,39677864 -8/7N/8/4n3/1k5b/4R3/K7/8 b - -,20,363,6179,118126,2002601,38742834 -7k/R7/6P1/2p2P1P/8/3b1K2/8/8 w - -,23,231,4515,42845,828407,8043903 -2bq1b2/4k1p1/1p1p1p1r/2p2Q1N/3p3P/N1P5/Pp3PP1/1RB1KBR1 b - -,25,1043,25886,1042258,27657634,1090994666 -5B1r/3k3p/7P/2Rp2p1/3rRP1P/2Np3K/8/2B5 w - -,37,429,14894,234954,8238306,153079298 -6q1/8/2P2P2/8/6kp/p1K5/8/8 b - -,26,178,4567,36849,911351,7563672 -8/8/4Q3/1kB4P/3P3b/2R5/8/1K6 b - -,9,435,3528,156802,1323643,56596146 -8/6p1/8/qR3k2/2K3n1/8/8/3b4 b - -,7,93,2960,30398,971182,11145937 -8/7N/8/8/1k5P/3R4/K6n/4b3 b - -,13,271,3801,78057,1160430,23759852 -8/6B1/1K6/4P1P1/P3qk2/3b4/2R5/8 b - -,30,602,18515,358703,10842723,209285093 -rnbq1r2/1ppp1k2/1b2p2n/pP3ppp/3PP3/5PK1/PBP1Q1PP/RN3BNR w - -,26,800,21175,664118,18469608,591122637 -7r/1rk4p/p7/npp1p1bP/2Pp4/PN3K2/RP2B1Q1/6N1 w - -,26,857,23431,732594,21402000,655862621 -6B1/k7/8/8/1pP5/5n2/8/1K2N3 w - -,14,185,2660,30709,470865,5259378 -2b1k1nr/p5bp/n2p1q2/p1pPp3/P1P3p1/Rr6/1P1NPPBP/2B1K1NR b Kk -,46,1069,45541,1089112,44033818,1081856348 -rnb1kbnr/ppq1pppp/2pp4/8/6P1/2P5/PP1PPPBP/RNBQK1NR w KQkq -,27,734,20553,579004,16988496,494216738 -8/2K5/8/8/8/k2p4/8/6n1 w - -,8,72,485,5403,35521,429752 -6b1/r2k4/4R3/N7/p2p1K2/P2P4/3r4/4N3 w - -,27,571,13490,323519,7341207,186485031 -r1b1kb2/p2p3r/4N2p/1p1ppppP/1n6/P3P2R/1PPB2P1/RQ2KBN1 b Qq -,26,891,22229,781301,19901798,711868944 -3N4/3k4/n1r5/4Q2p/7P/2R1B3/8/3K4 w - -,49,683,30591,409940,17506453,249442059 -rnbqkbnr/pppp1ppp/4p3/8/4P3/5P2/PPPP2PP/RNBQKBNR b KQkq -,30,751,22822,586355,18209820,483925829 -6B1/B3k3/7R/4nP2/7K/8/1p6/8 b - -,16,413,6375,169786,2862161,76929297 -N5nr/bp4q1/7k/5Ppp/ppP2BPN/3B3P/P7/R2K3R b - -,30,976,29323,927833,28631437,903103444 -4kb1r/rb4pp/p1n2p2/2PppP1P/Q1pBP1R1/N4K2/P2P4/R4nN1 b k -,22,736,18333,643467,17349441,629269743 -r1bqk1nr/3pbppp/ppn5/2p1p3/QPP3PP/4P3/P2P1P2/RNB1KBNR w KQkq -,33,951,31537,917769,30575622,916451465 -7k/3r3B/8/P4K2/1p5p/8/R2b4/6N1 w - -,18,405,7621,174509,3571259,80538258 -6k1/8/8/1K2P3/1N1R3P/2p2p2/8/5r2 w - -,26,358,8864,131557,3133272,49069802 -r1r5/6k1/5b2/1p6/2Np2P1/1RN2KB1/8/1r6 w - -,36,1488,48819,1988941,62158299,2480264960 -rnbq2r1/p2pb3/1p3p1k/1P1p3p/3p2P1/2P3K1/4BBN1/2R4R w - -,36,999,30467,843986,25652407,726072871 -rnb1k1r1/p2p1p2/1p6/2b3pp/2P2qP1/1PNPP2n/P1RK3P/1QN1BR2 b - -,44,1065,45259,1158499,47904946,1289487534 -2b3r1/2Np1p2/6k1/pr6/P1P2PPp/1P1P3P/R2KN3/Q3n1n1 b - -,31,1049,29361,932393,26107556,807012313 -r1b1kb1r/p1p1np1p/4p1p1/1p1p2q1/4P1PP/N2B4/P1nPKP2/R1BQ3R w kq -,26,976,24471,924900,24820328,946657362 -R7/8/8/1pkn2r1/6p1/1K6/6r1/8 w - -,15,405,4948,135946,1696877,47657535 -3k4/rb2b1rp/p1n2pp1/2PppP1P/Q1p1P1R1/N7/P2PKB2/3R1nN1 w - -,39,1055,39395,1089533,41786856,1191888962 -r7/n3k1b1/p2p4/P1pP4/2K5/P6N/3BB2R/6Q1 b - -,25,1011,21649,829009,17352916,659325759 -2k4r/p2n1p2/1pp1p2b/1n5p/1P4P1/1BP4K/P4r2/2R3NR b - -,46,961,42248,936472,39859992,940301238 -4k3/1B5N/Q1r2b2/P2pp1P1/1R5p/N1P4P/4K2R/8 w - -,42,758,31147,561590,23261775,405879997 -rn2kbnr/pp2q1p1/2ppbp1p/P3p3/5B2/1P1P2PP/R1P1PP2/1N1QKBNR b Kkq -,30,868,26010,782152,23875737,739439186 -rnbqkb1r/1pppp1pp/7n/p4p2/3P4/1P3N2/P1P1PPPP/RNBQKB1R w KQkq -,31,644,19743,454114,14225456,357469114 -2b2b1r/r3pk2/p1qp1ppn/1pPP3p/2P4P/N1N1P1P1/P4P2/R1BBK1R1 w Q -,31,1083,32819,1105171,33186031,1106828809 -2k5/8/4p3/4P2p/1K2P2P/3B1N2/8/8 w - -,21,103,1986,11113,201517,989059 -rn1qkb1r/2p1pp1p/4b1p1/pp1p4/1P1Pn1P1/P4Q2/2PNNP1P/R1BK1B1R w q -,34,1080,36303,1168613,40800142,1336336335 -r1bqkb1r/p1pp1ppp/1pn2n2/4p3/P2P2P1/7B/RPP1PP1P/1NBQK1NR b Kkq -,32,897,29728,868546,29484812,898416251 -2R5/1k2N2b/5P1N/6r1/2p3K1/2P5/8/2r5 w - -,5,151,3291,90615,1946846,53567270 -2b1kbnB/r1pqp3/n2p3p/1p1P1pp1/p1P3P1/PP2P2P/Q4P2/RN2KBNR w KQ -,30,689,21830,556204,18152100,497167912 -3k3r/1r5p/p6P/npp1p1b1/2Pp4/PN3K2/RP2B3/6NQ b - -,31,648,19685,481420,14295450,385973914 -1rr2bn1/1p2p2k/1P3pp1/1PPb3p/1n3P1P/8/R7/4K3 b - -,31,585,18128,290674,9060060,141733021 -5b1r/6k1/pp1p3p/PP2n1pP/2bP1Rp1/1R1BK3/2P4N/2Q5 b - -,22,886,19564,751129,16838584,635964358 -2k5/4B1Q1/p3b3/P7/1r6/3p4/8/R1K5 w - -,31,744,22831,483641,15153259,306263812 -rnbqkb1r/pppppppp/7n/1B6/8/4P3/PPPP1PPP/RNBQK1NR b KQkq -,17,574,11015,367804,8115152,270199459 -r7/5b2/p4n2/P1kPP3/2p4p/7N/2BK2P1/3N2R1 b - -,27,693,17556,469907,11549711,316110231 -2kr4/8/pb6/PppR1pP1/8/R3B2b/1P1QK3/2r5 b - -,29,871,24457,779389,22270631,736011023 -k7/8/7R/4N3/2K4b/8/5b2/8 w - -,24,344,8162,130815,3073747,50896824 -r2k1bn1/pB5r/5p1p/1Pp1p2Q/P1P4P/2R2N2/8/2B1K1NR w - -,42,813,35480,667804,29800465,574041820 -B6k/8/1p2p2n/Pp2P2p/7P/Q3P3/4K3/3bN3 w - -,5,69,1962,27575,797499,11621621 -2b3n1/r1Npk3/2n2ppr/pPb3p1/P2p1P2/2R2Q1P/3BP3/4KBNR b K -,30,1076,30185,1114122,31965009,1194564397 -5N2/4k3/B3n3/1r6/P2P4/1Pp2P1p/7P/K2Q3R w - -,26,616,18223,383144,11960420,237739733 -rnbq1b1r/2pppk2/pp6/5ppp/P1PP2n1/2NQP3/1P3PPP/R1B1KBNR w KQ -,36,1086,38696,1177972,41709294,1290710565 -2r5/7k/2B4r/6np/p6p/3pP3/8/bR4K1 w - -,29,953,23043,802392,18001961,636087099 -rnbqk1nr/1ppp1p2/p2bp2p/6pQ/8/2N1P2N/PPPP1PPP/R1B1KB1R w KQkq -,39,972,37730,969284,37552285,1007078922 -1b6/2Q2b2/8/2k4P/4r3/r7/4p1K1/8 b - -,5,108,3381,68691,2212402,44007612 -7q/k4r2/4p1p1/p2n3p/PBp4P/2rR1PK1/1R6/5B2 b - -,45,1274,50773,1434854,54497462,1531799093 -6bR/8/4k3/1P6/5B2/3B4/5K2/n7 w - -,37,321,11323,127721,4399831,54491183 -7k/8/1p3n1P/1P1p1bKb/3R4/5B2/3pr3/8 b - -,38,758,26537,496189,16823423,314430625 -8/6r1/3NN2k/p4p2/P4Pp1/2K5/8/8 b - -,14,293,3512,67550,857900,15298306 -8/8/kp4r1/7R/2P1B3/5Np1/8/2K5 w - -,37,434,14743,199320,6268727,91682558 -r4n2/7p/2p2k1b/p6P/5pP1/4R3/K4B2/8 b - -,18,412,7515,176068,3444664,78840139 -4r3/8/7N/p1b2p2/P4P2/5k2/8/1K6 w - -,9,288,2678,72498,688538,17612433 -8/4r3/3k3P/1K6/8/8/5pN1/6b1 b - -,24,230,5533,54004,1373649,14188732 -8/4n3/4P1P1/P2N4/3K4/5k1p/2b5/8 w - -,14,280,3625,70760,932458,18037833 -r1n2B1r/2k4p/4p1pb/pP2pBP1/1P3P1P/P2p2R1/5K2/RNB5 w - -,36,806,28212,660294,22715899,552383697 -8/b3k3/5n2/1P4P1/2Pr3N/p4R2/7r/6K1 b - -,41,637,20416,320688,10091997,162855453 -Bnbqk3/2pppp1r/pp3bp1/7p/PP4Q1/B3P1P1/3P1P1P/RN3KNR w - -,40,990,37850,943860,35495800,906741778 -B4B2/5r2/p3N1kp/PP2b3/2r5/2Rp4/3K4/8 w - -,34,1368,42732,1537142,47259396,1586179572 -N1b2knr/pp3qbp/5p2/2ppp1p1/1P4P1/2P1PP1P/P2PK1B1/R1BQ2NR b - -,27,701,19586,528999,15066186,424425453 -7r/nk3B2/p7/PP1r4/7P/1PB5/N6K/8 b - -,32,807,22559,557879,15099968,367405357 -k7/8/1nb4p/3p2B1/8/3p4/5K1n/N7 b - -,19,281,5584,80434,1647848,24155599 -8/p6k/P7/1p1p4/3P2Qp/7P/3qN2K/B7 w - -,21,272,6067,92560,2064235,33583683 -rnbqk2r/1p1p1pbp/4p2n/p1p3p1/2PPP1P1/5P1N/PP1K2BP/RNBQR3 w kq -,30,871,27199,817512,26109023,811434183 -6k1/8/3b4/6K1/7B/8/8/1b6 b - -,23,153,3291,33957,707722,7707387 -8/2k5/5B1p/P4prP/2n2R2/3Pb3/4N3/4K3 b - -,30,788,21222,528186,14049104,341072179 -rnb1qbkr/2ppp3/p7/1p3ppp/P1PP4/4P3/NPK2PPP/RQn2BNR w - -,27,789,22128,677806,19668469,624306144 -1n6/1P4k1/bB6/4nPr1/2p4P/4Kp2/8/5R2 b - -,26,571,14308,316621,8018182,179333859 -bbn4r/q1N4k/8/p2P1N2/2PBp2p/3BPP2/P3K1p1/2R2R2 w - -,45,1401,52359,1785976,66044334,2381936291 -7q/1k3r2/4p1p1/p2n3p/PBp4P/2r2PK1/1R1R4/5B2 w - -,29,1105,30367,1144473,32054000,1197886804 -b7/1rb5/8/3K3k/8/2p5/1n6/2r4n b - -,34,156,5832,20281,794789,2959395 -r1qk1bn1/pp5r/B4p1p/1Pp1p1Q1/P1P3bP/R2PB3/8/1N2K1NR w - -,35,1165,43536,1406059,54191193,1742398790 -k3b3/8/8/3p2p1/2n5/N2p4/7n/4K3 b - -,24,139,3087,21675,456570,3578998 -k5nr/rn1N4/8/1p1PK1Pp/1p1P3P/1P3q2/8/6RR w - -,19,633,11093,377895,7164045,249447725 -r7/1b1npkbr/p2p4/P1p4p/6P1/4P2N/2K2PP1/R2NQB1R b - -,42,1314,49147,1613253,57938812,1975981688 -1r6/5b1k/1p4RP/1Pnp1p2/6N1/1p1p2BK/6B1/8 w - -,29,670,18448,423759,11641651,270244767 -8/q7/5k2/p5r1/PP1rp1P1/1KnP1N2/R2Np1B1/1R6 w - -,32,1474,43511,1979363,56738280,2566622072 -3n4/6k1/PPp2b2/2B3pN/r7/N7/5K2/8 b - -,6,144,3492,79514,1965833,44682754 -1r4k1/p7/P1P5/2P1r3/1R6/3B1KP1/1P6/8 b - -,25,639,14168,340940,7543424,177745394 -2b1qb2/4n1kr/ppnp3p/6pP/P2P2p1/1P2rP2/2P1P1RN/2RQKB2 w - -,18,680,13328,511193,11119161,428010028 -rnbqkbnr/1ppp1p2/p3p2p/6p1/6Q1/2N1P2N/PPPP1PPP/R1B1KB1R b KQkq -,25,1096,27771,1157565,30620511,1241961350 -8/5k2/p2p1n2/P1bP2Q1/P1p5/5KB1/4BN1R/8 w - -,38,632,24836,378439,14904619,222046732 -2k2q2/2P2rb1/3r4/1p1ppb2/Bp1P2n1/8/5BPR/5K2 w - -,21,854,16866,690173,14231684,589290494 -3N3k/4r3/2Kn3B/8/6p1/6P1/8/1b5R b - -,31,708,14523,330141,7310199,167590835 -3n1kr1/3N4/5n2/1B6/8/8/1K6/8 b - -,5,100,2057,39236,877347,16188424 -5R2/1r5k/4b3/2p2P1P/8/R5P1/1r5p/7K b - -,34,782,22770,508390,14341477,318495952 -1k6/1P6/8/2P2p1p/8/8/1N5r/B5K1 b - -,14,97,1372,16387,236769,3593120 -6N1/8/4P3/P4n2/4k1P1/3b3p/8/K7 w - -,9,173,1704,33394,368443,7347229 -1Nk3nQ/7p/4pppb/3r3P/2pPPqP1/1b3P2/PR6/2B1K2R b - -,41,1227,45437,1419154,50366572,1622523992 -8/6b1/2k3P1/1b4R1/5N2/1N6/2K2b2/8 b - -,29,764,19723,496827,12766003,316254949 -r4bnr/1Bq1k1p1/5n2/1pp1pp1P/p2PPPb1/P1P5/1P3Q1P/RNB1K1NR w KQ -,34,1499,50901,2159399,73338011,3038485452 -2b5/4R3/r6k/P2p1pn1/1p3PPp/1P5P/8/2K2n2 w - -,20,447,7485,171162,2752668,64698766 -8/1b6/2kb4/2P3P1/8/1p1K3N/8/N3R1b1 b - -,23,513,11513,242437,5613042,117954945 -rnbk1rq1/3p3p/2p1Q3/p1b4n/PP6/2Np3n/1R1P3R/2B4K b - -,46,1583,67072,2107257,89914869,2774536796 -2n5/3R4/r1kb4/P3p2p/3P3p/2PbP3/1K6/BB3N2 b - -,30,633,15810,355398,8842726,205254422 -1rbk1bnr/pp1p1ppp/n1q5/2p1pP1Q/P1B1P3/2PP3P/1P4P1/RNB2KNR w - -,40,1135,44932,1262150,48978974,1399141722 -8/2k4p/7P/8/1r6/5Rb1/8/1q5K w - -,2,84,879,33171,404208,15287243 -8/r3R1P1/1k3P2/2q5/7p/2B4K/8/8 w - -,29,910,22521,688926,17042012,519836527 -2b1q1r1/1r1p1pk1/1N6/p7/PnP2PPp/1P1P4/1R1K1B1P/Q1N3n1 b - -,35,828,27046,671306,23399466,603788022 -8/3r3r/1q3k2/p3p3/P2Q3p/1PnPppPN/1RKN2B1/6R1 w - -,39,1630,61802,2460084,91326769,3544106555 -r1b1k3/p2p1Nr1/n2b3p/3pp1pP/2BB1p2/P3P2R/Q1P3P1/R3K1N1 b Qq -,26,1078,27519,1138857,29537643,1224563392 -r1bqkbnr/p1Qpp1p1/n4p2/1p5p/7P/3P2PN/PPP1PP2/RNB1KB1R b KQq -,19,781,17100,667856,16476592,630091061 -r3k3/n5bQ/p2p4/P1pP4/2K5/P6N/3BB2R/1q6 w - -,34,1097,33036,943507,30206426,827486835 -4n3/4p1n1/8/p2kb2p/P1p1N2r/Rr1pp3/6K1/1NB2B2 b - -,39,742,24852,499600,17024186,360435458 -4r2B/R1p5/P1r1P1p1/6k1/n7/1P6/1b1K4/4N2N b - -,36,669,21598,439712,13950513,302730424 -1n5k/1b2pr2/1B4p1/1P1p1p2/2p2PpP/1p2P3/3b2KN/1N1R1R2 w - -,25,643,16901,443735,12315379,329312991 -4NR2/7k/7p/1p1pP1BP/P7/1R1p4/b1nK1PP1/8 w - -,36,410,14349,151020,4834770,53627687 -rnbqk2r/pppp2pp/4p2n/5p2/2P5/b3P3/PPQP1PPP/1RB1KBNR b Kkq -,33,926,31073,906324,30628460,919292560 -6b1/1r1Bk3/1p2P2N/P4P2/6PK/8/2n3b1/4BR2 w - -,24,544,14059,329426,8919299,216032130 -r7/2k5/Pp1n4/2p4P/2P5/3R1Np1/6B1/3K4 w - -,26,582,16072,295823,8117577,147319846 -r3kbr1/2p1pp2/2nqb1p1/pp5n/1PPp4/B2PPP1P/P2N2BR/1R1Q1KN1 b - -,43,1138,48679,1331778,56323141,1595940583 -4R3/7k/5n1p/6p1/1p1P4/1nQ2Kp1/2P5/6R1 w - -,42,716,24935,401381,13851172,219374198 -r7/7k/5b2/1p2B3/3p2P1/1R6/3N1K2/3r4 b - -,36,963,31019,795144,24844344,625383361 -5B2/P1k5/7P/4P3/2K3P1/8/2b5/8 w - -,19,252,4691,57476,1132800,13293676 -6r1/1B5k/n7/8/8/7K/3p4/1b1R4 b - -,28,503,13577,265788,7417473,150607452 -8/8/7k/7p/7p/4P2n/5R1K/1B6 w - -,24,142,3041,22492,465313,3874012 -rnkq1bnr/p3ppp1/1ppp3p/5b2/8/2PQ3P/PP1PPPB1/RNB1K1NR b KQ -,29,927,25822,832461,23480361,768311001 -r4b2/nb2N1kr/6p1/pPpPpp2/1P1N1P1p/P3P2Q/5KPn/R1B3R1 b - -,31,1099,32452,1165579,35341431,1283606460 -7r/8/7k/8/n3q3/6KB/8/1bR5 b - -,45,806,34541,635736,26253827,493796589 -r1bqkbnr/p1pppppp/8/1p2n3/4P3/N6P/PPPP1PP1/R1BQKBNR w KQkq -,27,670,17605,458679,12863387,352565008 -1r1k4/2R4p/7P/3p4/8/pp4K1/8/b7 w - -,22,366,6839,126158,2184045,44018754 -8/5R2/2K4r/7k/7p/p7/8/8 w - -,7,92,1477,21051,353006,5643978 -1n4nr/2k4r/1p1q4/P2p3p/Rp1PPPPP/1P6/3N3R/2N2K2 b - -,32,841,27222,726542,24101665,648386858 -N4b2/7r/qB3P1k/8/PpP3P1/1B6/2n5/1K3R2 w - -,29,749,20414,578637,15569976,465385206 -b3k3/8/1N6/2r5/2p2P1n/4B2B/p7/2KR4 b - -,29,876,23803,688367,18685863,536367517 -r1bqkbnr/ppp2ppp/2np4/4p3/3PPB2/8/PPP2PPP/RN1QKBNR w KQkq -,40,1375,53941,1847613,71349363,2459614646 -2b3k1/r1nN4/1P1P4/NP1n2p1/p4p2/P1bK2P1/6r1/5R2 b - -,44,1094,45385,1123101,45655261,1120033587 -rr6/1kb2Q2/p2B2P1/Ppp2p2/3R4/RP5b/3K4/8 w - -,43,709,28941,568192,22530882,484671979 -4k3/8/2r5/4N3/P7/1P1B1PRp/1Kp4P/8 b - -,19,541,9173,257672,4472979,123932618 -8/k1n2B2/8/p3p1r1/3r2p1/8/1b2K2B/3N4 w - -,21,709,14063,463777,9292568,303910593 -3n2k1/8/3r4/5n1R/2p5/2N5/8/1K3B2 w - -,26,630,15685,377216,9479531,225897241 -K6k/8/8/1Pn5/5N2/8/8/8 w - -,11,111,1138,10982,113292,1153793 -8/2r1b1kB/2b5/7n/3p4/2p4r/1n3K2/7R w - -,20,871,15030,652424,11402728,494574126 -7r/1q6/7k/8/n6K/8/6B1/1bR5 w - -,24,944,19193,738935,14849333,574432522 -r2k3r/4pP1p/pn1q2pb/1p2p1P1/1PP2PBP/P2p2R1/3K2N1/RNB5 b - -,30,923,27062,826996,25011217,767553363 -3n4/k5r1/4B3/p3p3/2r3p1/4K1B1/1b6/3N4 b - -,37,716,24818,492542,16304628,329490341 -1n2rk2/r7/1pb1p2p/p2R1N2/P1P1pP1p/8/4PKB1/b5nR b - -,39,1186,43928,1299413,46701392,1357153177 -5N2/k5b1/5R2/1P6/1K4nP/8/8/8 b - -,13,289,4075,81399,1238165,24675114 -3k1b2/R7/2P4n/3prP2/8/6n1/2KN4/8 w - -,29,718,18168,460574,10500200,272170516 -3rnb2/4p3/7p/p2k1n2/P1p4r/2ppp3/1B1NB1K1/RNQ5 b - -,36,934,31323,812504,26782878,720463585 -3n4/k1r5/1r6/K3p3/B5pB/8/8/3N2b1 w - -,17,639,10557,366800,6388518,215866609 -1b6/8/4P3/1k6/3Q4/1K3B2/6P1/8 w - -,44,333,12412,114804,3979036,39029178 -2b1rb2/2nk3P/7p/2P1B2P/2p1p3/NR3N2/PR1P4/4K3 w - -,40,853,33277,747027,28888289,676712635 -1n6/rb4b1/1P1p1k2/pP2Pr2/2P1P1p1/BN2K1P1/1R4BP/7R b - -,8,282,8387,287802,8689389,300920064 -4b3/4k3/8/bP2Pr2/p3n2P/2B5/1K6/5R2 b - -,35,802,25191,552943,16936190,365173493 -8/7N/b1Np4/q7/5k2/6R1/8/2Kn4 b - -,33,759,23058,500342,14836063,311140267 -8/1pp2R2/1k4P1/1p3p1p/1n3P2/5r1b/8/1N1Kn1N1 b - -,29,523,13923,251721,6543361,121081033 -8/R1p5/Pn2P1p1/5k2/2r5/1PBNK3/5N2/b7 b - -,22,615,13865,364371,8314187,217598476 -bn2nbr1/2q1p1p1/2k3B1/2BpP2p/P2P4/2r2Pp1/2R5/3QK1R1 w - -,38,1018,36958,1022634,37081642,1067730667 -4N3/7k/7B/1p1pP2P/P7/1R1pnR2/b2K1PP1/8 b - -,15,439,5752,170330,2139543,62952695 -2b1k3/4p3/1r1nP1r1/p5pP/Pp6/1Q1n1P2/N3K2P/5R1R b - -,30,825,25169,731116,22166590,674789880 -1N1k4/6b1/P3p1p1/2PPr2p/5R1P/4B3/2nKb2R/2r5 w - -,30,985,26609,878484,22895022,760981395 -7r/8/1k6/6n1/2K3p1/8/8/8 w - -,6,168,1027,27110,159509,4107071 -3k4/3r4/p2p3p/Pb3P1P/1bP5/3p2pR/3R2P1/4K3 w - -,9,179,1972,44435,605160,14344563 -8/5bk1/1P4B1/p5P1/P3Pp2/8/7n/2b1KR2 b - -,20,252,5077,75097,1532452,25193756 -8/2k5/P7/2p5/P1P2p2/3N4/6K1/6R1 b - -,8,168,989,21995,133375,3068320 -3rk2r/p4pQ1/3p2pb/1pp3P1/P2p4/2n2R1b/1PKN3P/2B4R w k -,38,1049,37850,1032776,37185689,1017748582 -5B1r/2k1n2p/2r1p1pb/pP2pBP1/1P3P1P/P2p4/N4K2/R1B3R1 w - -,34,1003,32881,937008,30690059,863896985 -1k3N2/8/8/1P6/7P/1K2R3/p4n2/8 w - -,26,356,8198,117673,2545537,39657527 -4N2k/8/7p/np1p3P/P2pPR1B/4R3/b4PP1/3K4 b - -,14,442,5998,182662,2539412,76449154 -rn1q1bnr/3kppp1/p1pp3p/1p3b2/1P6/2P2N1P/P1QPPPB1/RNB1K2R b KQ -,29,900,25008,781431,22075119,699176752 -1n1qkbnr/r1pp1p1p/pp6/4p1p1/4b3/5PPP/PPPP4/RNBQKBNR b KQk -,37,905,32153,810205,28232983,748729213 -4n3/R7/P1p1P3/5kp1/1r6/1PB5/3K4/b1N4N b - -,25,658,14793,392706,8854557,233991631 -k5n1/2P5/4KNq1/rp1P3p/1p2R2P/1PR5/8/8 w - -,27,642,14301,369752,8984898,240832167 -8/Q7/5kp1/p2p1p2/5P2/Rp2B1P1/4KbP1/8 w - -,32,254,8122,76951,2463889,26660785 -1r2rb2/np2p1k1/1p3pp1/Pqpn3p/1P5P/3P1PPb/1R2B3/2K1R3 b - -,39,793,31100,653338,25769350,562272495 -6Q1/b7/2k1P3/8/8/8/4B1P1/3K4 w - -,29,317,9732,101389,3162179,34399005 -8/6R1/6n1/8/k7/8/K2b4/8 w - -,12,197,3019,47112,741630,11681671 -1rb1k1r1/p1p1p2p/1p2P2b/Q2p1np1/NP1B1pP1/P1nP1P2/3qN2P/3R1K1R b - -,41,1348,53178,1678867,65118358,2029277798 -rn4r1/p3k2p/2pb4/rB3p2/6PP/6B1/1P3P1R/2K3R1 b - -,38,1033,36033,996595,34176434,963682834 -B5r1/7k/8/2n5/8/7K/2bp4/3R4 w - -,17,583,10941,358166,6997318,223860471 -8/7k/4P3/4P3/P7/7N/N7/5K2 w - -,14,69,1068,4663,77778,357669 -r1b1k1n1/4qpr1/n1p1p3/1pbP4/Pp5P/N1PPBP1B/8/R2QK2R b KQ -,42,1735,73970,2972410,127494816,5062231267 -8/6kR/1P4B1/p2b2P1/P3Ppn1/8/4K3/2b5 b - -,3,74,1497,29787,595363,11519617 -4k3/1r1bp3/3nP1r1/p5pP/1N6/3nQP2/4K2P/1R5R b - -,35,1376,46504,1794836,59383110,2263140853 -r1bqkbnr/pppppppp/2n5/8/P7/2P5/1P1PPPPP/RNBQKBNR b KQkq -,22,461,11095,260364,6781695,175929387 -8/8/k7/2R5/N2p2PP/3K2b1/8/5b2 w - -,4,71,1453,24579,498115,8545408 -1k6/8/4P3/7B/8/3Q4/2K2bP1/8 b - -,14,544,6237,220826,2436868,82237630 -r2nk1n1/p7/q1bp3P/2p1pp1p/pPPN1pP1/3P3R/2K1PP2/R1Q2B2 w q -,40,1394,53196,1816796,68205186,2317441449 -4q3/k7/4P3/3B4/1R4p1/K7/5bP1/4Q3 b - -,26,961,23085,809570,19454567,664123919 -b1k5/n4N2/P7/2p5/2PpPb2/3P4/1p4Kn/8 b - -,26,270,6619,61437,1590395,14647807 -1n4nr/p2r1B1p/1p3kbb/2p5/3pPBPq/2QP1K1P/P1P5/RNR5 b - -,33,1094,33686,1105403,35110215,1148913510 -7R/1K6/p2Nk3/pN6/P3n3/8/5N2/5r2 b - -,22,768,15853,516331,10526626,326213648 -k5N1/4Bn1p/P1b5/2qp4/8/3p3K/7n/8 b - -,36,472,16597,226282,7854003,109740648 -rn1qkbnr/1p2pp1p/3p4/5Pp1/P1p3b1/1p1P3B/2P1P2P/RNBQK1NR b Kkq -,34,891,31739,863095,31746960,907637426 -2n2k2/3bp3/N3P3/p6P/4K3/1Q2RP1p/5r2/6rn w - -,33,1162,35231,1148886,34634338,1099487166 -4rbkr/p1n1p1pp/3P4/8/2pQ1P1P/P1N1P3/7R/1RB1KBN1 b - -,19,1073,20252,1092785,21684674,1128206828 -3qkb1r/2pbpp2/r1n3p1/pp5n/1P1p4/B2PPP1P/P1PN2BR/R2QK1N1 w Qk -,26,836,22297,772298,21221352,772525328 -2qnrbnr/ppp1k2p/3pbp2/2P1p3/P7/BP4PN/3PPP1P/RNQ1KB1R w K -,26,725,20934,603013,18620768,548905963 -1k6/3B4/4p3/4P2p/4P2P/1K6/7N/8 b - -,4,68,325,5361,25680,428031 -r1b2bnr/4pk2/3q1p1p/ppppP3/PPPn2pP/N1NQ1PP1/RB1P4/4KB1R b K -,39,1440,50949,1912964,66573058,2524624646 -1r2kb1r/4p1pp/2p2p2/p1p4n/q1PnPP2/R6N/3P3P/1NB1KB1R w k -,22,793,17229,607956,13982703,491211713 -4k3/8/r7/PB2N3/8/1P3PRp/2K4P/8 b - -,4,108,1213,37238,462060,13780931 -2Q5/8/8/5n2/7k/K7/8/8 w - -,24,246,6428,59963,1528883,13869988 -1k6/5r2/4K3/8/3P1N2/P7/5R2/8 b - -,16,318,4910,104603,1603414,34854812 -2r5/pb4r1/2pk2p1/1pnB1P1P/PP1N3R/1PB4P/4K3/1r6 b - -,44,1279,50917,1481545,56876130,1674763786 -2K3k1/N7/p7/p7/P7/8/8/3N1r2 w - -,11,183,2263,39099,508375,8806646 -8/3bk3/1N6/1P1pnB1P/P4p2/1p1P1R2/8/5K1N w - -,27,532,13927,264430,6824541,125694198 -3rk2r/p4pQ1/3p1npb/1pp3P1/P2pN3/5R1b/1PK4P/2B4R b k -,32,1392,38303,1561118,42657172,1679170375 -b4rn1/p3k3/2qN3P/2P1p3/p1P2ppp/Q2PRP2/1K3P2/R4B2 b - -,34,996,31658,984666,31668153,1026877259 -r1q4r/pbpk1pbp/P2p3n/4p3/2pPP3/6PN/1PPBBP1P/nN1K3R b - -,33,1114,36256,1168704,38643738,1212821410 -rn4n1/4b2r/p2ppk1p/1b1P1pp1/1P2P2P/p2R2P1/2K1NP2/1N2B2R b - -,27,884,23553,726111,20210190,604620138 -rnb1kbnr/1p1ppppp/1q6/p1p5/2P2P2/8/PP1PPKPP/RNBQ1BNR w kq -,25,794,20715,630906,16967616,520874238 -rnb2b1r/3p4/pp3p1k/1P1p3p/3p2PN/2P2B2/5BK1/1R3R2 b - -,21,690,14746,493636,11332263,387673941 -rnbqk1n1/1ppp3r/p3pb1p/5p2/8/2NPPQ1N/PPP2PPP/1RBK1B1R w q -,33,933,32009,917717,32341797,947644880 -8/6kb/4p3/4PB1p/1p2P2P/8/8/2NK4 b - -,10,121,1068,14075,128099,1726542 -8/8/1k1n4/1p5P/1p3K2/rP1R1R2/8/3N4 w - -,21,443,11125,216179,5931858,110536788 -k4B2/5n1p/P7/3p1N2/b7/3p3K/1q6/5n2 w - -,18,811,12597,497488,7804170,290296888 -3n1Bk1/8/5B2/5P2/3K4/5p2/8/8 b - -,8,138,1162,22177,218276,4137446 -r7/pbk3r1/2p3p1/1pn2P1P/PP5R/1PB4P/3KN1B1/r7 b - -,43,1176,46659,1343863,51165328,1520255592 -1NR5/8/3p1P1k/p3n2r/3K4/8/7p/3b3n w - -,20,473,8003,208183,3526333,96309903 -8/2n4k/1p6/8/8/5p2/K7/6n1 w - -,5,75,418,6433,36067,585996 -8/5k2/2B5/P3P3/8/5N2/4K3/2N5 w - -,27,160,4322,20975,562438,2694836 -b6b/1P6/5P2/4k3/2P3P1/NpNR2p1/4K3/8 b - -,8,285,2895,96373,1233447,38981843 -8/2k5/5q1R/2PP4/4p2r/2K2Pp1/6p1/8 w - -,6,220,3574,108187,1777632,52618321 -8/2p5/1p4P1/rp3p2/1k2bP1p/4n3/7K/N7 b - -,32,154,4036,26138,700612,6156431 -3kr3/1r5p/p6P/npp1p3/2Pp1b2/P4K2/RP2B3/N5NQ w - -,19,562,12668,380839,9478526,285162647 -rn1qkb1r/1bp2ppp/8/pp1pp2n/2PP1B2/5P1P/PP1QP1P1/RN2KBNR w KQk -,32,1254,40050,1564987,50852309,1984963918 -8/5n2/2Bp1N2/4k1n1/4p3/1q6/8/3K4 w - -,4,140,2108,61492,869787,25223985 -2b5/6P1/1k6/1R6/8/1Nb3N1/8/2K1b3 b - -,5,134,2800,68174,1516394,39083749 -B1k5/1r6/P4r2/P7/1P5P/7K/4NB2/8 b - -,28,658,16388,391634,9469235,230830224 -7n/8/P3Rn2/1k6/1p6/7P/2B2K1R/6N1 b - -,14,419,5230,163815,2163059,68100156 -8/p6k/P7/1p1p2Q1/q2Pn1Rp/7P/8/B1N3K1 w - -,30,439,13052,217121,6640616,118431241 -rn6/p2p2p1/1pp1pqk1/5p2/P2R1n2/N3Pb2/3K1PB1/2BQ2N1 w - -,32,1072,33620,1105618,35362563,1153502717 -rnbq1b1r/ppppp2p/4kp2/4N1p1/1P1P2n1/P1N1P2P/2P2P2/R1BQKB1R w KQ -,42,971,39093,925873,36215950,883283352 -2b1kr2/r2pbp1p/2n3N1/QpP1qP2/PP1p4/4pP2/3NK1BP/R1R5 w - b6,42,1733,66312,2597219,96767010,3673908617 -4k2r/B1pR1rn1/5p1p/Q7/PP3Rn1/2p4q/4P2P/4K3 w - -,40,1040,36754,1011671,34606373,993097428 -8/3k4/4p1B1/4P2p/4P2P/2K5/1p6/6N1 w - -,16,139,1950,20107,265908,3346646 -2RK4/8/P7/8/b7/8/8/7k b - -,10,122,1304,20942,235056,4111163 -8/8/1qB1k3/1p6/3p4/1p6/4K3/8 w - -,17,296,4165,91405,1151927,27001740 -b7/3q4/R7/pP5k/5P1p/3B4/8/1K6 b - -,30,665,17030,353415,9065672,183403787 -2b5/r1nN1k2/1P1P4/6p1/pP3pn1/P2KB1P1/3N2Br/b6R w - -,42,1632,60994,2353206,85237115,3245599090 -4r3/8/3K4/1k6/1r4p1/8/8/8 b - -,28,104,2954,11228,320333,1437361 -4k3/8/4n3/1B2N3/P7/1Pr2P1p/K1p4P/6R1 b - -,4,138,2760,80741,1714859,46015431 -rnbqkbnr/p1p1pppp/1p6/3p4/2P2P2/N2P3P/PP2P1P1/R1BQKBNR b KQkq -,30,750,21890,586034,17626869,498650662 -8/1Br1k1bN/p2p4/P3p1P1/7p/N1P4P/8/1R1Q1K1R b - -,18,757,13244,560695,9826880,417857764 -4rb1r/pppk1n1p/3p1p1n/2P1p3/PQ1P2q1/BP4Pb/4PPBP/RN2K2R w K -,34,1302,43316,1615249,54682721,2018749388 -6r1/1k6/2n1NP2/3p4/8/6b1/7n/3K4 w - -,13,411,5251,170635,2185141,68722116 -3r4/3n1k2/p2p4/P1pbp3/R6p/4PPrN/B2K1QP1/3N3R w - -,34,1034,35679,1098748,38476108,1186070586 -1r2k1n1/p1rp2p1/1p6/4Np2/2bq1PPp/2pQ4/Pb2P1BP/R1BK3R b - -,45,1371,61198,1939118,84708659,2773359535 -1n4k1/1b3r1p/rp2p3/p1P3b1/P1P1pP1p/4Nn2/1Q2PK2/3R1BBR w - -,45,1444,58148,1902199,71586291,2352782520 -r2qkbnr/2p2p1p/p1np4/1p2p3/1P2b2p/5PP1/P1PPK3/RNBQ1BNR w k -,24,882,21589,788530,20740744,758096288 -q1b2bnr/r3p1k1/p2p2p1/1NPP1p2/2P4P/N3P1P1/PB1KBP2/R5R1 b - -,5,221,5372,214474,5778151,221041699 -1rb1qb2/ppppp1p1/5rkn/P7/P1P3Pp/B4P1P/R2P3N/1N1Q1KR1 w - -,28,755,21876,588321,17942558,496369573 -bN6/8/4kb2/6P1/N1P5/Np4p1/4K3/3R4 w - -,32,675,18978,392965,10542743,219183245 -8/rk6/2p2pr1/p2P1P2/P1P1P1q1/1P3p2/N7/1RBK2R1 w - -,26,619,15476,424340,10786051,316913669 -5nkr/7p/3b2b1/Bpp1n3/P1PpP3/3P2K1/8/1N2R3 b - -,24,445,11499,226734,6084657,124625930 -r1b1kb1r/2Bp3p/1p2P1p1/p4pq1/P1p5/5Nn1/Q3KPPP/R4B1R w kq -,5,179,5706,195394,6612528,226353468 -5k2/6p1/3K4/7R/P3pP1p/1b4qn/3N3P/7q b - -,42,912,34419,688179,25963561,496101104 -rnb2k1r/1p1p1pp1/p1p2n1p/2b1p1P1/P4P2/1qB1P3/2PPQ2P/RN2KBNR w KQ -,36,1559,56128,2293549,83128822,3275368833 -2b5/6k1/4R1n1/r4pP1/1p1p1P1p/1P5P/8/2K2n2 w - -,17,454,6384,167967,2270258,59341434 -8/8/4P2k/8/4K3/5pB1/8/8 w - -,18,99,1640,10460,172130,1182236 -2b5/r1nN1kb1/1P1P4/1P4p1/p3Kpn1/P3B1P1/3N2Br/7R b - -,42,1330,52391,1642322,62680660,1948561184 -rnb2b1r/pp2p1kp/6pn/2pN1p2/P4B1P/1qPP4/4PPP1/RQ2KBNR b KQ -,32,1163,36029,1334908,41662004,1559999831 -1nq3nr/3k3p/bp2p1p1/r1B5/P1p1pbP1/1Q3P1P/3PPKB1/5RNR w - -,34,1273,38398,1448864,44164653,1681183753 -3nB3/k5r1/8/p3p3/3r2p1/4K1B1/1b6/3N4 w - -,18,620,10783,359893,6547017,214357559 -1R6/1k2N2b/5P1N/6r1/2p2K2/2P5/2r5/8 b - -,4,98,2596,55759,1471510,31592687 -1rk5/4b3/1p3R2/1P3p2/B6K/3Np3/P2n4/R7 b - -,21,472,9783,242516,5188125,138856262 -1N6/8/8/1B1k4/r7/1P3PRp/7P/2K5 w - -,28,438,11140,157364,4051492,56798973 -r1b1kb1r/p1npp1pp/2p2p1Q/1p6/1q1PPP2/4B3/2P3PP/RNK2BNR b q -,33,1019,32318,1058260,33840276,1153734175 -5Br1/3k3p/7P/2R4P/2rp1Pp1/3p4/N3R1K1/2B5 b - -,15,526,9167,305168,6039275,195563634 -6n1/5k2/1P6/8/3P3P/8/3N2K1/2Q5 b - -,10,330,3047,98338,890837,27961214 -R7/8/8/2p3N1/2P5/6K1/6R1/1k3q2 w - -,32,486,10380,177278,4023833,73184117 -2n5/6bB/r7/P1k1p1pp/6P1/2PPP2P/1R2b2N/B3K3 w - -,25,652,16626,412224,10731721,263414671 -3B3R/1N1k4/4r3/8/p1bp1p1N/P2P4/5K2/6r1 w - -,22,713,16680,507971,12481425,363871551 -2b1k2r/p6N/B2pp3/P3r3/5bPp/N5RP/2P2B2/3Q1KR1 w - -,41,1120,43834,1204810,47678374,1315691996 -5k2/6p1/pp1N2q1/1R3pn1/P3PP1p/1b2K2B/1bq4P/7R w - -,29,1371,32369,1559496,37373418,1788480514 -4r1k1/p7/PRP5/2P1r3/8/5KP1/1PB5/8 w - -,22,458,8992,200110,4051060,92026863 -1r2kbnr/p1q1p3/3p1pp1/1pn4p/1PPPN1bP/4P1P1/P4P2/RNB1KB1R b KQ -,44,1212,47752,1321161,51064726,1437100243 -rn2qb2/N2k1b1r/Qpp1p3/5Ppp/3PPP2/2p4P/PPB1K2N/1RB2R2 b - -,29,1261,35428,1516657,44447406,1883631564 -1n6/rb2B1b1/1P4k1/pP2p3/2P1P1p1/1N3rP1/1R4BP/4K2R w - -,33,1062,33452,1054513,33482039,1044867594 -2b5/8/6nk/r2p1pP1/1p3P1p/1P2R2P/8/2K2n2 b - -,3,45,1115,14541,361211,4623778 -4kbr1/rp3p2/1n4pp/pPpp1P1R/2NP1p2/P1N5/2P1P3/BR2KB2 w - -,35,781,26757,614621,20795073,495364450 -rnbk1r2/p2pb2p/2p1p3/1NP4n/P7/1P1p2qn/1R1P3R/1QB4K b - -,50,790,37137,653072,29130290,574966041 -8/6n1/1p1kN3/8/5P2/2K5/8/8 b - -,10,140,1453,18537,200737,2425074 -8/K7/1P6/8/8/7k/8/8 w - -,5,25,150,1004,7242,44194 -rnb1kbr1/pB2ppp1/1q6/2pp3p/2PP1Pn1/P3P3/RP2K1PP/1NBQ2NR b q -,42,1351,51157,1658614,61272934,2008946030 -8/4k3/N7/1p1KP3/2N4P/2P2p2/R7/1r6 b - -,18,474,7998,201440,3301987,82267343 -4k3/r6B/p2P4/pNp3P1/P3n3/1n4NP/1b6/4KR2 b - -,32,870,23378,631753,16560205,446728579 -b3nbr1/k4Bp1/1q2p3/3p3p/P2P4/1K3nQ1/6R1/8 w - -,3,120,3143,117817,3377528,126292707 -r7/1k6/6P1/5P2/7p/q1B4K/8/4R3 w - -,20,603,13866,433786,10333286,328933245 -8/2p5/1p6/1p3p2/5P1p/r1k2n1K/8/5N2 b - -,25,131,3245,21816,504349,3827575 -8/5k2/4q3/8/2K2B2/8/8/6Q1 w - -,6,162,3947,94418,2334614,51318676 -3k3r/6R1/2P4n/3p1PN1/1b6/5NP1/4n3/3K4 b - -,26,653,14322,360618,8156094,203007120 -1n1qkb1r/r2b2np/pp2pp2/1Npp2p1/2B2P2/1PPPP1PP/P2B1Q2/R4KNR w k -,32,816,26796,742729,24837968,730946584 -8/2K4R/8/5bq1/P5k1/8/3B4/8 b - -,23,468,12899,254564,7209903,142874843 -bk6/b6r/7p/B1P4P/4p3/P7/3nK2N/6R1 w - -,30,540,14322,296004,7354121,164025034 -2k2r2/6p1/6p1/r6P/1P1PP3/8/3K4/3n2N1 b - -,36,496,16452,209109,6595995,82380893 -3r4/8/8/2k4r/6p1/8/5K2/8 b - -,34,216,7095,27501,889212,3981732 -2B1k1n1/r1n5/2p2pr1/1PBPp3/5P1P/2pP3q/8/1NR1KQ1R b K -,44,1711,71820,2699378,110477465,4102583438 -4qb1r/6k1/ppnpb1np/6pP/PP1P2p1/4rP2/2PKP1RN/1R1Q1B2 w - -,22,1034,22793,1046505,24444328,1092425957 -7r/1k1n1p2/1p6/pPp1p3/B5K1/2n1b2R/PN6/4R3 b - -,40,1075,38634,1049439,34817760,958715308 -4k3/r6B/p2P4/p1p3n1/P7/N5NP/1b1n4/4KR2 w - -,31,905,24955,702236,19164545,526307700 -1rbqkbnr/pp1ppp1p/n1p3p1/8/3P1PP1/P7/1PPQP2P/RNB1KBNR b KQk -,23,598,15419,435984,12129296,366042959 -8/1k6/6P1/5P2/r6p/1qB4K/8/R7 b - -,36,635,21084,418569,13625769,283060198 -2K5/R7/3B1q2/P7/8/3b4/6k1/8 b - -,39,783,28037,505821,17148186,309252509 -3k4/5P2/8/1P6/7P/pK2R1n1/8/8 b - -,10,239,2166,51092,510263,12017460 -2b1k3/r1np3r/1P1P4/4Npp1/pP3Bn1/P2K2P1/8/bN3B1R b - -,34,961,31578,908552,29369347,855195015 -r1bqkbnr/pppppppp/2n5/8/1P2P3/8/P1PP1PPP/RNBQKBNR b KQkq -,22,679,16154,504493,12885948,411324737 -7r/pk1n1p2/1p2p2b/1Pp5/B5K1/2n5/Pr1N4/4R2R b - -,43,1247,52481,1483973,60550115,1686485368 -rnbqkb1r/2pppppp/1p5n/8/1PBPP3/p4N2/P1PNQPPP/1RB1K2R b Kk -,23,806,19569,704424,18374337,676968611 -3N4/5r1k/2BB4/Pp1R3p/8/2K5/8/2b5 w - -,35,869,26842,614904,19300935,422988414 -1k4r1/3B3P/p2n4/Ppp4R/1P6/1P5P/1N3Kb1/1rBr4 w - -,35,1403,43682,1689140,52071356,1959484588 -3nQ1b1/8/4p2k/4P2p/1p2P1BP/8/8/2NK4 b - -,9,233,2007,54886,528783,14763049 -8/4Bk2/B1n4p/Pp1p3P/P2pPp2/3R4/b2K1PP1/R4qN1 w - -,36,1035,29077,791055,21743979,575887058 -5n1k/8/6p1/4p2p/B6P/4K3/8/2r1b3 b - -,25,255,6578,71768,1881650,20697804 -6nr/p1k5/2b5/2Pqp3/Q1PPNp1p/4RPPB/1K2R3/8 w - -,48,1352,60364,1851755,79393107,2544595718 -8/k3b3/8/8/8/2K3p1/4B3/3r4 w - -,13,346,4215,106487,1321729,33017499 -2k5/6R1/8/2PP4/1K2p3/5Pp1/4r1p1/8 w - -,23,331,6471,109499,1971975,36470344 -8/4k3/4B2R/5P2/1p3B1K/3n4/8/8 w - -,29,297,8581,84142,2424783,22869398 -rn1qkbr1/1pp1pp1p/4b1p1/p2p4/3Pn1P1/P4Q2/1PPNNP1P/R1BK1B1R b q -,35,1129,38155,1287446,43564432,1512202030 -3k4/8/6n1/7N/8/2Kp1N2/8/8 w - -,19,221,3941,44607,772468,9129015 -2k5/6Rp/2b4P/3p4/pr6/1pb2Kp1/8/8 w - -,16,429,5883,156807,2170834,57928942 -8/7k/3R1nBp/pp1p2pP/3P2p1/6N1/2P2KQ1/R7 b - -,3,135,1371,56650,529904,22368757 -r1bqkbnr/pppppppp/2n5/8/3P4/2P5/PP2PPPP/RNBQKBNR b KQkq -,22,639,15321,459575,11884685,369044250 -6N1/6k1/P3P3/1p3P1K/1B2B3/8/7R/1n6 b - -,6,223,1472,52174,382217,12976235 -7k/B7/6b1/8/1b2K3/4n1p1/6P1/8 w - -,5,137,1117,26682,265340,6081477 -k4N2/8/1qP1K2n/1p1P3p/1p5P/1P6/8/r1R1R3 b - -,27,591,15944,356458,9777509,220884160 -8/8/2r5/5k2/4N3/1P1K1P1p/7P/8 w - -,14,229,2941,46573,585474,9331669 -rnbq2r1/p2p4/1p3p1k/1P1pp2p/3P2P1/b1P3K1/4B1N1/2R1B2R b - -,33,885,26355,708309,21317500,586586786 -rnbqkbnr/ppppppp1/8/7p/1P6/5N2/P1PPPPPP/RNBQKB1R b KQkq -,21,483,11260,280455,7154758,190659130 -3r2k1/p7/PRP5/2P1q2r/8/6P1/1PB2K2/8 b - -,48,818,34199,618697,24652870,460944217 -4N3/8/5P2/p7/Pb6/3rK3/6k1/8 w - -,4,100,766,17554,167094,3785748 -Q1bq1b1r/6p1/1p1pkp2/2p4p/3p3P/NpP1n1N1/P4PP1/1RB1KB1R b - -,33,1241,37573,1449489,43912198,1716878559 -8/3k4/8/2b3b1/8/8/8/3K4 w - -,3,84,412,10474,49087,1176384 -r1b1q1n1/pppk1p1r/3p3b/3P2pp/4PpnP/N1P2PPR/PP2K3/2RQ1BN1 w - -,27,781,21814,653206,19205433,593257382 -rnbqkb1r/p2ppppp/1pp2n2/7P/8/P7/1PPPPPP1/RNBQKBNR w KQkq -,21,441,10464,244919,6367151,162456913 -k5n1/4b1b1/3pb3/3P1Pp1/2P2RPp/p1N1K2P/8/1B2N1R1 b - -,22,656,14616,420458,9669579,273871494 -8/5k2/8/1K6/4qB2/8/8/6Q1 b - -,30,699,16936,417976,9336652,235857208 -r5nr/1b1p1p2/3qNk1b/pppP2p1/1nP4P/P4P2/2QRPK1P/5BNR w - -,39,1439,50649,1811642,62252429,2206799839 -4Q3/3k4/8/2n4P/3P4/N3K3/8/8 b - -,3,70,622,15714,133053,3512423 -1Nb1kb2/2B1p3/P5p1/3PP1rp/2P5/6r1/3R1P1P/n1K4R w - -,30,781,21435,576202,16083362,446215260 -3BN3/7k/7p/1p1pP2P/P2p1R2/1n2R3/b4PP1/4K3 b - -,12,442,5358,180496,2289197,73389702 -4B2k/8/P2BP3/1p3P1K/8/6R1/1n6/8 b - -,6,211,1561,51134,403102,12815527 -8/n2k4/p2p4/P1pP2Q1/8/P1bK3N/3Br2R/3B4 w - -,38,871,31268,684193,25054554,539304247 -8/8/rk1P1pP1/p1p5/PNP5/1Pq2p2/1B6/1R3KR1 b - -,20,364,7994,162392,3799493,84800727 -3q1b2/3b4/1pk2ppr/2ppQ2N/3p3P/P1P5/1pN1BPP1/1RB1K1R1 w - -,52,1359,62706,1755453,77385890,2278608084 -8/8/1k2P3/4b3/Q3B3/1K3p2/6P1/8 b - -,17,581,6885,234358,2857726,94290724 -r1b3r1/1p1p2k1/nb6/Bq2p1p1/P1pQ3p/4nNPK/2P4P/RN5R b - -,45,1738,72622,2673665,108481201,3915954612 -3r4/3n1k2/p2pb3/P1p1p3/R3P2p/5PQN/B2K2P1/3N3R b - -,22,853,17725,676360,14607927,554153815 -1b2Q3/5b2/8/2P4P/3kr3/r7/4p1K1/8 w - -,20,680,13227,450064,8857033,295565558 -1r3b2/8/p2pbk2/Pnp2Q2/3P4/P2K1Bp1/3B4/R5NR b - -,4,153,3708,165350,4064185,179532526 -5n2/3r2kr/8/3R3p/p1p4p/4PBb1/3RK3/2N5 b - -,29,820,23585,730339,21565674,690321215 -N5k1/8/8/8/4BQK1/1p6/7p/8 w - -,39,255,9719,87947,2974360,35171599 -2r2b2/p1qb4/1p2pk1r/1PpBp2p/P1K2P1P/8/2PQP2B/RNn3N1 b - -,32,935,29681,907444,29135861,904283779 -b6b/1n6/P4P2/4k3/1pP3P1/N1N3p1/4K3/3R4 w - -,34,436,13032,197686,5418455,94721685 -7b/2r2P2/2R1Q3/5B2/1p4Pk/8/4K3/8 w - -,43,739,31981,602333,26048128,506553699 -1r1qkbnr/1p1bpppp/1pn5/2p5/2PpP3/P2P2PP/1P1N1P2/R1B1KBNR w KQk -,20,479,10151,269333,6066856,171852624 -2b1k3/p3p1rp/1r2P3/1npN2p1/1P4P1/PQ1P1P2/4n1KP/3R3R w - -,33,991,32916,993720,33806954,1031531742 -1B3k2/6r1/8/1p1pp1N1/6K1/6P1/Rp4N1/6br b - -,34,639,21088,464595,15122478,358971447 -r7/3k1n2/2qN4/2P1p3/Q1PPRp1p/K4PP1/8/R7 b - -,26,796,20049,637847,16701244,542729916 -2bq1b2/8/1p1k1ppr/2ppQ2N/3p3P/2P5/PpN1BPP1/1RB1K1R1 b - -,4,184,4964,205245,5935558,237508881 -8/1r6/8/1k6/pN1P4/P5K1/7r/2Rb4 w - -,19,537,9443,251401,4630597,124933081 -5b2/1q3b1N/1k4p1/2pp3Q/2Bp3P/P1P3P1/2NK1P2/2r3R1 b - -,32,1104,36854,1276940,43058808,1491778478 -8/k7/8/2n5/1K6/4R3/2p1b2P/8 b - -,26,469,10544,176534,3926168,63763867 -rnbqkb1r/4p1pp/1ppp3n/p4p2/P2P3P/1P3N2/2PNPPP1/R1BQKB1R w KQkq -,24,576,15324,381462,11060069,288137338 -1k3b2/8/1p3p2/pPn1p1r1/B7/2RN4/P1R4K/8 b - -,28,599,15274,369333,9049346,235064557 -8/8/np6/2pk2N1/1p3P2/8/4K3/8 b - -,9,131,1311,17226,183549,2295646 -1k6/4n2P/p5r1/P1pb3B/1P6/1PR4P/1N1B1K2/r5r1 b - -,54,1601,73300,2183986,94298740,2844139676 -8/8/2kbb3/6P1/2P2N2/1p6/4K1p1/N3R3 b - -,28,571,15780,344493,9349542,205240825 -5k2/6p1/6q1/pp2Kp2/P1R1PP1p/1b3N1n/7P/3R1q2 b - -,43,1181,47933,1162024,46757761,1090009509 -1rb2rk1/1p1qppb1/1pn1Pnp1/2p4p/2Pp3P/PN1PBPP1/1P6/R2K1BNR b - -,27,852,24004,727414,21654124,641220479 -r3q2r/pb1k1pbp/P1pp3n/4p3/2pPP3/6P1/1PPBBP1P/nN1K2NR w - -,32,992,30753,966136,29392257,940071649 -8/5n2/3p1N2/4k1n1/q3B3/8/4K3/8 b - -,31,623,18395,322063,9434136,151289779 -8/8/1B6/3N4/5Pk1/R1r3pp/5R2/5K2 b - -,18,545,8798,263186,4257560,127954092 -2kNN3/r7/8/1P1P2pP/8/2n2rp1/8/K7 w - -,1,36,474,15018,207452,6280867 -5q2/p2Pn3/P4Pk1/Bp1p2p1/3P3p/7P/5R2/3Q2KN w - -,42,783,31901,617680,24748974,492055248 -1N1R4/8/P5k1/2r3b1/2B4P/3p4/K7/4N3 b - -,25,710,15740,438089,9714617,270742106 -4k3/8/p2R3p/P4R2/6b1/2Q5/7K/8 b - -,8,425,3472,164648,1477254,66398734 -1rbqkb1r/1p2ppp1/1pn2n2/2p4p/2PpP3/PN1P1PPP/1P2K3/R1B2BNR w k -,22,663,15826,485646,12185004,385589671 -5k2/6p1/8/4K3/b3pP1R/3q2Pn/8/1N6 w - -,13,450,5980,195572,2790381,88048588 -4r2k/3n1b2/1p5P/1P1p2B1/5RK1/3p4/2b3B1/8 w - -,27,764,18041,482052,11653408,306450824 -5R2/8/k2P2n1/1p6/1p1RN2P/1P3qK1/8/7r w - -,2,40,1017,19297,514532,9703618 -rnbqkb1r/pppppppp/7n/8/1P6/7P/P1PPPPP1/RNBQKBNR b KQkq -,20,401,8962,200647,4963473,122581649 -rnk2bnr/2q1pp2/2pQ2pp/pp6/1P5N/2PPP2P/P4P2/RNB1KB1b b Q -,28,1002,27640,960905,28434554,970730912 -1nbqkb1r/3pp1pp/1p6/2p1Pp2/rP1P4/pBB2N2/P1PN1PPn/2RQK2R b Kk -,26,751,19478,602092,16243598,528560999 -3n1k1b/8/P1p5/6p1/1P6/N7/3B1r2/2K2N2 w - -,17,469,8009,217778,3964108,106692995 -2r3nr/1bN1kp1p/p3p1pb/3p3P/4PqP1/3B1P2/P2P1K1R/RQB5 b - -,38,1203,43053,1437122,51608214,1792221503 -rn4n1/4b1kr/3pP2p/1b6/pP2PppP/p1R3P1/2K1NP2/1N2B2R w - -,28,801,22686,646112,18397225,537014133 -rnbqkbnr/1p1p2p1/4p2p/p1p2p2/7P/2P2P1N/PP1PP1P1/RNBQKB1R w Qkq -,24,667,16857,482676,13132163,388285670 -rn2k2r/4n2p/1p2p1p1/8/P2B2P1/2q4P/3bPKb1/3r1RNR w - -,18,1052,18276,1024402,19487771,1060583108 -r3B1nr/ppp2p1p/4k1bq/2b5/1n1pPpp1/3P1PP1/P1PNQ2P/R1B2K1R b - -,39,1135,42380,1275659,48042035,1491299599 -4k3/1B4bN/p2pp3/PRr5/6Pp/N1P4P/5K2/3Q3R b - -,25,1149,25191,1119902,23287643,1015014780 -5k2/1pB5/r7/3pp1K1/R7/6Pr/1p5P/nN2N1b1 b - -,36,916,30634,769341,25811439,650488000 -r2n3r/1bpk2pp/6P1/pP1N1p2/1b1p1qnP/1P1P1p1R/2P1P1B1/Q1B1RKN1 w - -,37,1758,58970,2740662,91290830,4178493281 -3k4/5K2/7r/8/3P1R2/P7/8/6N1 b - -,17,269,4249,75113,1178886,22239370 -1n2kb1r/1bB2ppp/r7/1p5n/p1pP3q/1P3P1P/P3P1P1/RNQK1BNR b k -,51,1700,81805,2662389,124570149,4016258887 -rnbqkb1r/p2p1ppp/1pp1pn2/8/P2N4/3PP3/1PP2PPP/RNBQKB1R b KQkq -,28,922,27379,914323,28128642,950090524 -3k1q2/3B4/3p2Nn/3P2b1/4pP1R/7p/5r2/2nK4 w - -,21,724,13704,472353,8900459,309144052 -5bk1/3n1b1r/1p1p2Bp/Pp4pP/3P2p1/1R1QKR2/2P4N/8 w - -,38,745,28638,573561,22042806,456625466 -2b5/r5k1/1n1P4/NP1n2p1/p3KPN1/P7/2rb4/5R2 w - -,26,1193,27997,1223913,28524782,1199634287 -8/4k3/8/1Pn5/5B2/8/5K2/1b6 b - -,22,411,8195,134137,2615660,40335582 -1R6/5p2/2rk4/p2r3p/1b2p3/p1PN3b/R2K1PBP/8 w - -,29,889,25129,775593,22669081,706141180 -r2qk1n1/p2pNpp1/bprb4/8/3p1PPp/2p1B3/P1Q1P2P/RN2KB1R b KQq -,37,1295,48315,1649814,60806198,2077910875 -3r4/5k2/4N1N1/3q4/P1R1p3/1p1P4/6K1/1r6 b - -,41,1077,38667,930928,33841449,783503978 -r1bqkbr1/p1p2ppp/n2p4/1p2p3/P2PP3/3Q4/1PPB1PPP/RN3KNR w q -,42,1266,51786,1630302,64926234,2104938318 -rnb1k2r/3pqpb1/1P2p1Q1/p1p2Np1/1P3P1p/B2PP3/2PK2PP/RN3B1R b kq -,38,1366,45003,1664982,54024105,2033528709 -3R1n2/7p/r4k1P/p1p4P/K4p2/8/8/4B3 w - -,22,326,6732,110124,2229652,38504519 -8/3N4/8/3k4/8/rP3P1p/7P/2K5 w - -,13,154,1811,26610,309674,4791308 -rnbq1b1r/2pk2p1/1p1p1p1n/1N2p2p/p2P3P/2P1PQ2/PP3PP1/R1B1KBNR w Q -,39,995,38274,1024011,39304543,1094593883 -4b3/4k3/8/1P2Pr2/p6P/6n1/1K6/4bR2 w - -,16,492,7370,219506,3305862,98643800 -Q1b5/q3b1k1/pp2p3/1Pp1P2p/P3B2P/1n1K4/4P1NB/2r2N2 w - -,26,848,21392,675675,17909958,562881444 -3n4/k4r2/3r4/pK2p3/B5pB/8/8/3N2b1 w - -,15,550,8668,310244,5345041,186392825 -1n2k2r/rb1p2bp/1PQ1p1Pn/p2P1p2/1P2P3/5Nq1/P4P2/RNB1KB1R w KQk -,56,2414,121299,5060975,241773574,9879139633 -2k5/4P3/r7/1PNP2pP/6p1/5r2/nK6/8 b - -,32,579,14803,250268,6055912,98641214 -r7/1pk2p1p/3ppn1b/6BP/P1pQ2B1/R2P1n2/2K1P3/6qR w - -,42,2001,75322,3355827,126543470,5360448645 -rn2kbnr/p1p1p2p/4Bp2/1p4p1/1q2P3/NQ5b/PP1P1PPP/R1BK2NR w kq -,39,1120,38890,1151975,39601674,1203871707 -2q1kbnr/rpn2p1p/3pp3/5PpB/P1p5/1P1P4/1B2P2P/RN1QK1NR w Kk -,36,1079,39126,1199779,44286056,1394826108 -6k1/5b2/1P4B1/p5P1/P3Pp2/7R/3n4/2b1K3 b - -,18,395,6985,139590,2629044,52663645 -3n2k1/8/4p1b1/1p2P2p/Q6P/4P3/8/2N1K2B b - -,18,579,9155,284583,4391499,134127982 -3r4/n7/3P1kp1/pP3p1r/P1b2P1p/3RP3/6PQ/2b1K1R1 b - -,33,702,22946,502014,16359274,384825448 -b4N2/1k6/7P/P7/5b2/3r4/4p1K1/8 w - -,9,284,2423,71175,666227,19589466 -4B3/8/7B/4P1P1/ppK1k3/PP6/7p/2R5 b - -,11,287,3195,86554,1092067,28947278 -7n/2q5/3p4/3Bk1N1/8/3K4/8/8 b - -,24,464,10015,169804,3787363,61281909 -rn4nr/3bb2k/1R1pP3/4N2p/pP2PPPP/p1N5/2KB3R/8 b - -,23,845,21217,761219,20068120,711586435 -4q3/8/7B/4P1P1/pK2k3/PP4R1/8/8 w - -,17,334,5306,109149,1817004,37637053 -Nb2n3/4B1qr/1p5k/5P1P/1pP3pN/p4R1P/P7/R1K2B2 b - -,30,745,22222,594848,18343565,513686346 -6k1/5R2/5b2/5b2/3p4/B5p1/K5P1/8 w - -,19,348,6487,110572,2199544,36801159 -1K2k3/8/p1N5/p7/P7/8/3N4/4r3 b - -,16,272,4293,68703,1101439,16885237 -r2q1bnr/3Qp1k1/5p1p/pp1P3P/Pp2b1p1/N1N2PP1/2RP2B1/2B2RK1 b - -,26,975,25091,947122,25280339,963772288 -2b1kb2/3np3/P1p2rp1/B2PP2p/1rP5/1N1R2P1/p4P1P/2K4R b - -,32,936,30848,919098,30754640,925258114 -3kqQ2/2n1p3/r2p3b/3P1bpp/ppP3P1/PP2PN1P/3NKP2/2R2BR1 b - -,30,1031,29103,1011703,29467967,1033347390 -1nb2b2/r1B5/1P4k1/pP2p3/2P1P1p1/1N2r1P1/1R4BP/5K1R w - -,26,916,24006,811453,21995248,722745522 -4r2r/pppk1n1p/3b1p1n/Q3p3/P2p1Pq1/BP4Pb/4P2P/RN2KB1R b K -,47,1336,56595,1671759,68738250,2103814861 -rnbr4/1ppp2k1/1b2pq2/pP4p1/P2Pp2p/1QB1nP1K/1RPNB1PP/6NR w - -,23,983,24318,985905,26550774,1046167043 -R7/2k5/3b4/p4p2/4p2p/R1r2N1B/3K1P1P/1r6 b - -,41,989,33509,836965,26747851,690234613 -b7/5nb1/P1pBkP2/8/p1P3P1/6p1/2N1K3/1N1R4 w - -,38,587,20686,325349,10801248,180997192 -r7/n3k3/p2p4/P1pP1Q2/8/P2KBB1N/1b4pR/R7 w - -,49,1041,49280,1065966,49793049,1107271428 -8/1P1n2k1/1B6/4nP2/2pK3P/R4p2/8/6r1 w - -,27,804,19377,544763,13305953,356093287 -8/4rN1k/4N3/p4p2/P4Pp1/2K5/8/8 w - -,20,219,3625,50060,781198,11309975 -r1b1kbnr/1p1pp2p/2n3p1/p1p2p2/q4P2/2QPB1PN/4P2P/RN2KB1R b KQkq -,37,1241,44732,1452510,51516316,1692172053 -1k6/8/3r1pP1/p1p5/P1Pq4/1P3K2/N7/R1R5 w - -,16,464,7007,216424,3689142,114023525 -4b3/8/7P/8/3k4/r5b1/4p1K1/8 w - -,4,160,648,23341,138593,4794553 -8/5R2/8/8/1k5n/8/K7/2b5 w - -,16,243,3763,58506,910691,14622592 -8/1K1k4/2N5/4b3/7P/5p2/7r/8 w - -,13,315,3405,84714,883660,21862487 -5b1r/5qk1/ppnpb1np/1P4pP/P2P2p1/5P2/2PKrR1N/1RQ2B2 w - -,6,267,7173,303223,8629020,350941330 -8/4k3/8/1p4r1/2n3pR/3K4/8/r7 w - -,13,482,6486,223030,3160005,103583675 -1r6/rkb2Q2/p5P1/Ppp2p2/1P1R4/R6b/3K3B/8 b - -,18,882,17658,798703,16981339,733393459 -r7/3k4/8/1R6/5P1p/p3K1b1/B7/1r6 w - -,28,854,20061,578342,13212097,374317866 -1b2b3/1R2P3/6r1/r3k2P/2P5/8/4pK2/8 b - -,43,669,25688,411283,15083911,248241694 -rnbqkbnr/p2pppp1/8/1pp4p/8/3PQ3/PPP1PPPP/RNB1KBNR w KQkq -,34,797,27674,719243,25761048,720914462 -8/6k1/4P3/8/8/4Kp2/8/4B3 b - -,8,119,747,10353,76331,1078862 -r3k3/3N1N2/3P4/pp6/4B1rp/P3q2P/1P1BPK2/R5R1 w - -,4,110,4371,124599,4779551,138435631 -2Q2r2/p6k/P7/2P5/r5R1/1P4K1/8/8 w - -,29,557,15984,287143,8323044,150945094 -1nr3k1/7r/1pb4p/p1P5/3b1p1p/4P3/5KB1/1N3RnR b - -,47,892,38453,822792,33510119,782314056 -1n6/4k3/8/7P/3P4/4K3/8/N7 b - -,11,121,1216,14224,150761,1782475 -3n4/k1r5/3r4/pK2p3/B5p1/4b1B1/8/3N4 b - -,44,522,20588,289299,10689776,169933967 -8/5n2/1N2bk2/PP1p3P/5pB1/1p1P1R2/6K1/7N w - -,25,366,9110,149104,3717989,62884853 -1Q6/3P4/p5k1/P3p3/n1p5/2N2K2/4B3/2b4R b - -,17,801,11985,535315,7929013,342406527 -6br/5k2/2B4p/r1P5/3p2KB/1P2p3/4R3/6nR w - -,34,640,21088,446327,14506590,335338293 -8/6r1/p2k1P1p/P6P/1b1p2R1/1b1p2P1/3R4/4K3 w - -,11,294,4208,108360,1881238,47935559 -8/3rk2n/3b1R2/1P4pr/2P4P/p7/8/4N1K1 w - -,22,444,8877,220699,4375912,119501009 -1rb1kb1r/p3p1pp/n4p2/1pppNn2/4P3/2PP3P/PB4P1/RN1QKB1R b KQk -,26,892,24047,808785,22760873,762738434 -3bb3/4k3/4P3/1P6/7P/p5n1/1K6/5R2 w - -,8,142,2596,51714,882577,19021723 -2kN4/5r2/8/1Q1n3p/7P/1K1RB3/8/8 b - -,24,949,15413,631251,9959952,409291606 -1Qn3k1/4pb2/N7/p4P1P/1R6/4K2p/8/1r4rn w - -,36,1262,40252,1435235,45602849,1622029513 -3k4/pr6/b2p3p/5P1P/PbBp4/6pR/1QPR2P1/3K4 w - -,34,790,25063,583895,18222256,423156034 -N1b3nr/pp2kq1p/5p1b/2ppp1p1/1P4P1/B1P1PP1P/P2PK1B1/R2Q2NR w - -,27,721,20446,544442,15938209,426750298 -rnbqkbnr/p2ppp1p/8/1pp3p1/8/P2P1N2/1PP1PPPP/RNBQKB1R w KQkq -,28,674,18621,490486,13982737,396149636 -2k5/4n3/5P2/3b2b1/1b1p2P1/3K3P/4N3/1B6 w - -,13,461,6186,204517,2999408,94351147 -1b2b3/4P1r1/8/4k2P/2P5/r7/2R1pK2/8 b - -,45,454,17395,225320,8434542,124238064 -1b2b3/4P1r1/8/4k2P/r1P5/8/4pK2/1R6 w - -,20,735,11872,430917,6978868,251094336 -k3b3/8/1n6/3p2p1/8/3p4/2N2K1n/8 w - -,11,224,2115,43234,409847,8491068 -4k1n1/8/2Nb4/5P2/p5p1/P2K2N1/8/2R2r2 b - -,25,699,17076,440166,10691703,261403971 -7k/8/1p6/1n6/1K6/5n2/8/5b2 w - -,2,44,165,3679,15254,347692 -r2q2nr/p1pbkppp/2npp3/bp4P1/3P1N1P/2N1P3/PPPQ1P1R/R1B1KB2 b Q -,28,1087,29800,1081824,31187304,1107261345 -8/P7/1k2n3/2R4n/1p6/7P/2B1NK2/6R1 w - -,50,797,37148,556607,23979893,357151491 -b3nbr1/2qnpBp1/1k6/3pP2p/P2P4/5P2/2Q3p1/4K1R1 b - -,29,956,24227,727613,19852550,581008734 -rn1qk1nr/pb2pp2/2pp4/1p4p1/1QN1P3/1P1P4/P1P1N1P1/2KRbB1R w q -,41,1396,53717,1852247,69769285,2425546576 -rnNk1br1/1b1pQ3/1P6/p1p1p1p1/1PPPPP2/7p/6PP/RNB1KB1R b - -,2,76,1888,70239,1783069,65357947 -r3k1nr/p3ppb1/1pp2P2/1n4pp/4N1b1/2Pq1Q1P/PP3KPR/R1B2BN1 w kq -,34,1568,49830,2191094,73511508,3119209483 -1k4r1/1b1B3P/p7/Ppp2nR1/1P6/1P5P/1N3K2/1rBr4 b - -,43,1327,49221,1521076,55892512,1722587801 -2k5/8/3R3N/4b3/8/3K1N2/8/6b1 w - -,27,523,14075,258582,6927582,126944680 -1k6/6N1/Pr6/1p6/4rb2/1p6/8/6K1 b - -,35,292,9290,84440,2692234,25871187 -2b1q3/p1r1n1p1/P1pp4/1pP2P1k/PB1P3p/4R2P/R3K3/1N2Q3 w - -,43,1053,42923,1093377,43414538,1135840544 -4k3/8/8/6b1/5b2/8/4K3/8 w - -,6,114,535,11520,61792,1341754 -4r2B/R1p5/Pnr1P1p1/8/6k1/1P6/1b6/3KN2N w - -,19,659,13249,442552,9483903,311467318 -r6r/1bp1knpp/1N4P1/pP3p2/1b1p2nP/BP1P1pqR/1QP1P1B1/4RKN1 w - -,31,1603,45495,2263658,66584818,3218953440 -1r1rk2B/p4R2/P1P5/1nPPb1q1/B7/N5P1/1P5P/4K3 b - -,39,1156,42299,1188671,43141902,1185333782 -1rb1kbnr/p3ppp1/np6/2pp4/P1PPBq2/2N1P3/1P3PPP/R1BQK1NR b Kk -,45,1780,76611,2966819,123783593,4736766152 -6k1/8/P2BP3/1p3P1K/2n1B3/6R1/8/8 b - -,2,80,800,28998,247711,8487857 -7k/2r4B/8/P7/1p2K2p/4b3/R7/6N1 b - -,29,603,15752,333248,8214048,176995876 -8/8/4n1k1/1n1P3p/6p1/7Q/1RPK4/8 b - -,24,681,13123,373397,6640982,193384773 -1n1q1br1/1b2pkpp/8/1pppP3/Br1P1pn1/N5P1/PBPN1P2/2RQK1R1 w - -,29,1081,32859,1191489,37591750,1342299031 -6k1/8/1P2B3/p5P1/4r3/6R1/1K6/8 b - -,5,144,2361,56072,898638,20787012 -N1b3r1/3p1p2/6k1/pr6/P1P2PPp/1P1P3P/R1nK4/Q1N1B1n1 w - -,27,764,20710,576080,16021457,448616402 -1q2R3/6p1/8/2K3k1/b5P1/8/2N2n2/8 b - -,37,614,21055,345784,11428495,189315855 -3rkbr1/3bpp1p/n4npB/pppN2q1/PP1P4/2P4Q/5P1P/1RN1KB1R b - -,41,1548,58793,2275739,87433202,3425158575 -3rnb2/3kp2p/7n/p7/2p2prP/2pp1R1K/PB1NB3/RN2Q3 w - -,29,861,25406,804293,25403793,832786756 -3kn3/R1r4B/Pp6/2p4P/1NP1p1p1/3R4/8/4K3 b - -,5,140,2136,58519,946368,26093483 -rn5k/3p3q/1pp1p3/pR1Q1pp1/P4P2/5P2/2NK2b1/2B3N1 b - -,28,1006,26000,917875,24034743,832239728 -8/1n6/8/5k1p/7P/8/8/1RK5 b - -,11,125,1318,21948,234194,4011681 -1n1qkbnr/rbpppppp/pp6/8/8/5P2/PPPPP1PP/RNBQKBNR b KQk -,25,477,12393,264026,7199884,168330788 -r1b3n1/ppp4r/1k1p1pQb/2q3pp/4PpnP/NPP2PPR/P3K3/1R3BN1 w - -,31,1191,35175,1338685,40837818,1553708687 -1nbqkb1r/2pppppp/r4n2/pp6/2PP4/7P/PP2PPP1/RNBQKBNR b KQk -,27,803,23065,704688,21109487,663590395 -3k2nN/8/3p2B1/3P2b1/4pq1R/1r3P1p/8/2nK4 w - -,16,603,8894,334742,5097304,192816698 -r7/2k5/4B3/1R6/3K1P1p/p5b1/8/1r6 b - -,31,882,25529,632057,18170573,420713911 -r1b2kn1/1p3q1r/p2p4/1N6/PbP1Np1p/3PPP1Q/1P1B2PP/1R1K1B1R w - -,39,1459,56061,2131758,80945281,3090685681 -8/8/4k2B/2K1P1PB/pp6/P6p/1P6/2R5 b - -,7,200,1347,39526,295432,8579845 -7R/4k3/7p/1p5r/r5p1/n3K3/8/8 w - -,13,318,4348,113035,1588127,42230029 -3R4/7p/3r1knP/p1p4P/K4B2/5p2/8/8 w - -,22,418,9100,176574,3792781,74260058 -rn5r/1bk4p/1Rp5/p1Pp4/P5n1/2Npq3/3P3R/2B3nK w - -,27,926,21545,760941,17282185,622928055 -8/k7/2B1p3/4P2p/K3P2P/8/8/5N2 w - -,15,48,695,2824,42897,189109 -rnbqkbnr/1ppppppp/p7/8/8/7P/PPPPPPPR/RNBQKBN1 b Qkq -,19,361,7754,165962,3992889,95412713 -5R2/1k5b/5P1N/5N1P/2p4K/2P5/1r3p2/8 b - -,21,453,9827,219086,5192347,115260378 -4n3/2b5/bpNk1n1p/3p1P2/P1B1pp2/1Pp4P/5K2/R3B1NR w - -,30,662,18074,403045,11256518,255826025 -r4b1r/3bpk2/p1qp1ppn/1pPP3p/2P4P/N1N1P1P1/P3BP2/R1B1K1R1 b Q -,34,1018,35230,1047073,36431794,1082880384 -1k2b3/2N5/8/3pn1p1/2n5/3p4/8/3K4 w - -,8,183,1346,32599,260711,6144442 -rnbqkbnr/1ppppp2/p6p/6p1/8/4P2N/PPPPQPPP/RNB1KB1R w KQkq -,28,501,15345,317204,10360381,239670673 -3n4/k1r5/1r6/K7/B3p1pB/8/8/3N2b1 b - -,41,619,22093,364067,12422691,215381413 -1n5K/3n4/1k6/2p5/2PpP2b/3P4/8/1b6 w - -,4,84,436,9416,49446,1095381 -rnbqkb1r/pp1ppp1p/5np1/2p2P2/3P4/8/PPP1P1PP/RNBQKBNR w KQkq -,29,776,23032,652632,20312976,605673485 -1n4K1/8/2k5/2p1n3/2PpP2b/3P4/8/1b6 b - -,24,103,2479,11658,278862,1402084 -rnN5/2k3rb/1p6/6pp/Qb1PPPP1/PP2BN2/b5K1/3B3R w - -,45,1405,60232,1860461,77555344,2410586498 -B1kr4/8/P7/PP6/3N3P/8/5r1K/6B1 w - -,5,110,2113,45832,968592,21095615 -2kr4/8/pb6/PppR1pP1/8/3KB3/RP1Q2b1/2r5 w - -,26,781,20195,612825,17360815,530999025 -8/1K5k/8/1P6/6N1/5nr1/8/8 b - -,16,232,4433,54115,1118886,12930188 -5bb1/k7/2K5/8/7P/4R3/8/8 w - -,18,271,4481,73426,1194034,20486399 -3Q4/4k3/8/2P5/1R6/1K6/8/4b1b1 b - -,3,96,1197,38271,515558,16572719 -1nb4k/4p1r1/5pp1/1Ppp3p/5PPP/Bp2P1K1/3bq1BN/1NR4R w - -,30,1165,28714,1111938,28380576,1090091844 -r7/p3B2r/1p4k1/q3p2p/Pb3pp1/1PnPQ2N/1R1KPPP1/1N3B1R b - -,41,1026,39620,1073189,41804862,1201784084 -N1r1QN1k/2n5/8/1B6/P2P4/KPp2P1p/7P/7R b - -,13,449,6120,217859,3171766,113448876 -rnbqkb1r/p2p1p2/1p2p3/P1p3pQ/1P1N1P1p/3PP3/1BPK2PP/RN3B1R w kq -,45,1225,53501,1503236,63998488,1853363449 -3n2k1/8/7r/5n2/2p5/2N5/2K4R/5B2 b - -,29,722,18175,444384,10818712,264659401 -4r3/rkp5/5pp1/p2P1P1P/P1P1Pp2/1P5q/N1K3R1/R1B5 b - -,37,932,32092,835793,27463996,740383821 -3n4/4Bk2/PPp5/6p1/3r4/N5N1/1b6/4K3 b - -,27,537,14862,305189,8301932,175527957 -8/8/8/1K3k1r/7p/p1b5/8/2R5 w - -,15,339,4991,110347,1738088,39280542 -1k6/4b3/6P1/N6n/8/5q2/7K/8 b - -,41,238,8034,61268,2105490,18044637 -6nr/2p1p2B/nr2b2k/1p2P3/1bq3pP/6P1/P4P1K/1R3BNR b - -,39,1036,42166,1120504,46697652,1250997708 -1r1k1b2/p3p3/n2n4/p1Qb4/1P1pp3/B2N1N2/5PpR/R5K1 w - -,44,1401,62078,1898084,83743911,2526110516 -r1b3r1/1p1k4/p2b1Q2/q1p1P2p/P4pnP/1PP2P2/3KN3/RN5R w - -,37,986,34512,938435,32143166,901110801 -3n1k2/8/P1p5/1P4p1/8/N1b5/3B1r2/3K1N2 b - -,31,541,16355,295741,8617166,164461175 -8/8/8/1p1N4/8/1k6/4K3/8 b - -,7,108,629,8773,52589,687352 -rn2kb1r/1b2p1pp/p1p4n/8/2PpQB2/7B/PP1KPP1q/RN4NR b kq -,24,1032,25731,1072853,28844821,1176354066 -1rb1kbr1/p2pp2p/2p1npN1/1R5p/1p1PPP2/4B3/2P1B1PP/1K5R b - -,31,1348,40959,1690376,50533834,2001147163 -k5N1/8/2r2P2/6r1/2pK4/2P5/8/4N3 b - -,25,218,5410,60445,1480797,18521977 -4r2r/Qppk1n1p/3b1p2/2B2n2/PP1ppP1q/6P1/R3P2P/1N1K1bR1 b - -,48,1398,64215,1928988,84645968,2617123240 -8/k7/4r3/1P6/2K3p1/8/8/r5n1 w - -,8,229,1330,37234,213803,6037672 -8/1r3P2/4R2k/1rp2P2/7P/1b4P1/7p/R6K b - -,4,130,2653,75293,1715152,47157360 -6br/5k2/2B4p/1rP5/5nK1/1P1pp2R/8/R3B3 b - -,25,967,23352,832707,21075446,715351309 -Qqb2br1/6k1/pp2p3/1Pp1p2p/P1K2P1P/3B1N2/2PNP2B/R1n5 w - -,34,712,23725,568621,19009231,496800075 -8/2k5/q6R/2PP4/2P1p1r1/K4Ppp/8/6R1 w - -,4,114,2752,72095,1705461,45300991 -7R/6p1/3q3n/8/4b3/1K4k1/8/8 w - -,14,678,8386,364395,4659774,188932022 -8/1N6/3p1P2/3b4/5knR/K7/7p/7n b - -,20,305,6212,113174,2409434,46657027 -b6b/5n2/P1pBkP2/8/p1P3P1/6p1/2NR4/1N2K3 b - -,13,395,5579,167281,2613118,77757824 -6k1/8/B6p/Pp1p3P/Pn1pPp1B/2R2R1N/b2K1PP1/7q b - -,26,711,17485,482046,11913935,330584002 -2k4r/p4p2/1pp1pn1b/1n3b1p/2B2B2/2P2rPP/PP4K1/R5NR b - -,44,1295,54907,1605646,67568329,1981297779 -1r2k1n1/p1rp2p1/1p4N1/5p2/2b2PPp/2pQq3/Pb2P2P/R1BK1B1R w - -,31,1339,37647,1590470,46079633,1913091510 -r2n3r/1bp3pp/1N1k2Pn/pP3p2/1b1pp2P/BP3PqR/2PPP1B1/1Q2RKN1 b - -,44,1135,45297,1200334,48267173,1321729425 -2r2nk1/7r/8/1R5p/p6p/3pPB2/1b3K2/R7 b - -,38,1405,48609,1646132,56340914,1794915264 -8/6k1/1P4B1/p2b2P1/P3Pp2/4bR2/7n/4K3 w - -,16,372,6062,134218,2403039,52398464 -5k2/n2BR3/3K3P/8/8/8/8/8 b - -,4,61,384,8360,53451,1160607 -1nq1kb1r/3bp1pp/rppp4/p5NP/P1PP1pn1/1P2PNP1/2Q2P2/R1B1KB1R b KQk -,24,1105,27746,1218947,32514738,1391368060 -7R/6P1/1P6/1r1b1k2/3p4/3P3K/8/Q2N4 w - -,35,829,28279,602145,20775925,423521341 -5k2/5Np1/pp4q1/3R1p2/P2KPP1p/1b5n/7P/3R1q2 w - -,27,1093,24338,973768,21444588,850240512 -rn2kbnr/p1q1ppp1/1ppp3p/8/4B1b1/2P4P/PPQPPP2/RNB1K1NR w KQkq -,29,827,24815,701084,21819626,622445426 -3k4/7r/5K2/8/3P1R2/P6N/8/8 w - -,17,279,4901,74205,1382811,20986896 -3r4/3npk2/p2p2r1/P1pb4/Rb4Pp/4PP1N/B5P1/2KN2QR b - -,37,853,29484,770692,26641842,764057754 -8/5Pr1/3b3k/2P5/1pR3P1/8/3K4/qB6 b - -,30,692,21512,460493,14277409,315042342 -8/q7/R1P5/5P1k/p6p/8/8/1K6 b - -,21,201,4488,50770,1145601,14783378 -8/n5bB/r7/P1k1p1pp/1R4PP/2PPP3/4b2N/B3K3 b - -,26,706,16548,439782,10469492,278444889 -8/8/8/3N4/kp6/3K4/8/8 w - -,15,69,929,4490,59162,344119 -4k3/rb1p3r/nPQPp1p1/5P2/pP3Bn1/5NP1/P3K3/bN3BR1 w - -,43,1603,66905,2398184,98350854,3456963539 -r1b4n/1pp3r1/pk1p1p2/4P1bp/1P3p1P/N2KnPP1/Pq6/2R2BNR b - -,50,1207,54515,1290097,57293636,1349621763 -r4bnr/p1pn4/b2Qpkpp/1p1p1p2/PPPPP3/R7/2B2PPP/1NBK2NR b - -,28,1415,35965,1726615,44863035,2069358982 -1r2kb1r/4p1pp/2p2p2/p1p2n1n/2P1PP2/2q5/R2PKN1P/1NB2B1R w k -,26,1094,23556,924631,20814062,784281022 -3k2b1/2p3r1/3N2r1/p5b1/pBPp1p2/P2P1P2/6q1/4K1NR w - -,22,745,13417,472257,8924275,320701202 -rnbqkb1r/pppppppp/7n/8/8/8/PPPPPPPP/RNBQKBNR b KQkq -,20,399,8957,197799,4933547,120120846 -rnb1kb2/p2p1p1r/6pp/1p1pp2P/4nq2/P1N5/1PPBPPP1/R2QKBNR w Qq -,27,1110,30509,1225510,35626649,1393377109 -8/2r2P2/7R/8/1pQ1B1k1/8/1b2K3/8 w - -,53,894,44642,812075,38641244,725249027 -4k1n1/8/2Nb4/5P2/p1K3p1/P5N1/1R3r2/8 w - -,31,772,20446,500671,12507591,304598578 -r4br1/1k2p3/2p2npp/PpnQ4/P5b1/2PPP1qP/5P2/RNB1KB2 w Q -,38,1935,61403,2903019,89326625,4018746673 -2R5/8/5n2/6b1/k7/8/K7/8 b - -,17,288,4670,75248,1235736,19612589 -7r/3n2kp/3b2b1/B1p1n3/P1PpP3/1p1P4/6K1/1N4R1 w - -,21,682,14728,466744,10193304,327177574 -5k2/2n4B/p2p4/P2P4/P1p4Q/4K2N/1b5R/4B3 w - -,42,632,23168,329598,12310325,170878970 -6BR/8/1k6/1p6/2P5/8/6p1/2K1N3 b - -,13,275,3334,78822,1045553,25437122 -4k3/8/5P1r/8/5K2/2N5/8/4B3 b - -,13,234,3455,60608,918854,16022993 -8/1B2k1bN/p2p4/PRr1p3/6Pp/N1P4P/8/3Q1K1R w - -,43,776,33057,590814,24866296,444560995 -rnbqk1nr/ppppp2p/7b/3P1pp1/8/2N5/PPP1PPPP/R1BQKBNR w KQkq -,28,507,15563,319039,10383685,234947987 -1r1k1bnN/8/3p4/1q1Pp1p1/2R2pBP/3n1P2/4K1R1/8 b - -,35,911,31249,790205,27787883,711598979 -rn1q4/p2p2p1/1pp1p1k1/5p1n/Pb3R2/N3Pb1B/3P1P2/2BQK1N1 b - -,41,1052,38151,1044830,36569110,1059826527 -rnb1kbnr/1p1pp2p/1q4p1/p1p2p2/P1P2P2/1P1P2P1/4P2P/RNBQKBNR w KQkq -,24,676,17007,482807,13023790,381110612 -3r4/6k1/8/6N1/Ppq1p3/2RP1N2/5K2/1r6 w - -,25,1090,24178,988061,21767914,857628382 -8/1N6/6k1/8/6Pb/3p2B1/5K2/8 w - -,12,132,2104,25265,426963,5575498 -8/8/3N1P2/p7/Pb1K4/r7/8/5k2 b - -,20,233,5063,54165,1182140,13175138 -8/8/3r4/5kN1/8/1P3P1p/4K2P/8 b - -,19,208,3373,37957,597394,6763362 -8/1bp5/1p6/1p3p2/5P1p/kn2N2K/8/r7 b - -,29,276,6537,52265,1428931,11644123 -1r1qkbnr/p1Q1p1p1/n2p1p2/1p5p/4N1bP/3PP1P1/PPP2P2/RNB1KB1R b KQ -,29,1149,29824,1140401,31235743,1173124487 -8/3bk3/8/bP2Pr2/p3n2P/8/3B4/1K3R2 w - -,26,833,19091,603337,13466562,422478902 -2b1kb1r/r1p4p/p1n1p3/1p3qPP/2Pp1B2/1N1P2K1/PP2Bn2/R2Q2N1 w k -,35,1564,46787,2035873,62824629,2675689885 -rn1q1b1r/ppp2k2/1B3n2/3pp1pp/P1P2p2/R2P3b/1P1QPPP1/1N2KBNR w K -,36,1690,59735,2688254,94521406,4130006716 -b6b/1n6/P1pBkP2/8/2P3P1/p1N3p1/3RK3/1N6 w - -,35,414,14030,191423,6320759,97827704 -k7/4N3/2n5/2P5/2B5/1p6/8/1K6 w - -,19,206,3743,33255,579546,5475787 -1rbk1r2/p1p1p2p/Qp5b/1nBpPnp1/1Pq2pP1/P2P1P2/1N2N2P/1R2K2R b - -,38,1326,48270,1625561,59153223,1957031578 -5n2/5n1k/8/5P2/5B1B/2K2p2/7r/8 b - -,23,522,12013,247912,5737518,114550001 -8/7k/5n1p/3R2p1/1p1P4/p1Q2Kp1/2P5/6R1 w - -,36,549,18982,266036,9170992,127026438 -rn3rk1/1b5p/1p2p3/p1P1n1b1/P1P1pP1p/8/1Q2P1NB/3RKB1R w - -,37,1383,45870,1619147,53012232,1821537012 -2Q3n1/4k3/1P6/8/3P3P/8/3N2K1/8 w - -,37,203,6978,46879,1520851,11806246 -rB2kbnr/pb6/1p3q2/5p1P/PpPp4/1Q5N/3PPP1P/RN2KB1R w KQkq -,35,1385,48116,1913479,66836437,2659333292 -2q5/8/2P2P2/8/p5kp/2K5/8/8 w - -,9,206,1791,43035,356010,8468810 -8/1pp3R1/1k4P1/1p3p1p/r4P2/P4P1b/n7/1N1Kn1N1 b - -,29,372,9897,157026,3903512,67963918 -r1bqkbnr/ppp2ppp/2n5/1B2p3/1P1pP3/3P1P2/P1P3PP/RNBQK1NR b KQkq -,31,912,28359,837429,26831328,806036073 -k3r1nr/8/4q3/np1P2Pp/1p1P3P/1P1N1N2/6K1/R6R b - -,33,1157,39565,1228577,42656562,1247774460 -7k/8/3Qr1Rb/p3p2p/PR2PP1P/2N5/4K3/6N1 b - -,12,585,7682,347034,4914686,212491689 -8/8/4kP1p/rpr5/6pP/8/2n5/6KR b - -,33,249,8316,96887,3094316,41509935 -8/8/3k4/1K2N2P/3b4/5p2/3r4/8 b - -,25,323,7568,89069,2241639,24749166 -1k6/7R/8/4bN2/8/3K4/2N5/4b3 w - -,32,640,18467,335988,9358591,166818098 -rnbq1b1r/pp1ppk1p/2p2p2/2N3p1/1P1PP3/P1N4P/2P2n2/R1BQKB1R w KQ -,42,1212,48586,1436113,57664017,1740641665 -5R1r/5N2/2k2P1r/8/2p2K2/2P5/8/4N3 b - -,18,390,7081,153428,3054878,67169027 -1k3b1r/8/p2p2Q1/Ppp2pP1/1R6/R2K3b/1P2r2P/2B5 b - -,33,941,27064,782913,22085581,654204729 -5kr1/1n6/8/7n/8/2N5/4B3/1K6 b - -,20,385,8527,161782,3797091,69382278 -rnbqkb1r/ppppp1pp/5n2/8/P1P2p2/8/1P1PPPPP/RNBQKBNR w KQkq -,21,504,12116,307209,8108637,218071184 -8/8/4n2k/7p/7p/3BP3/1R6/6K1 b - -,11,341,3268,84727,878341,21868988 -2n2B1r/2k4p/r3p1pb/pP2pBP1/1P3P1P/P1Np4/5K2/R1B3R1 b - -,26,1080,26737,1054736,26641208,1013366403 -8/5k1p/2bb3P/3pr3/p1p2P1r/1BR3p1/8/3K2B1 w - -,23,922,20396,776762,17176259,628583908 -1rr3n1/1p5k/1Pn1p1p1/1Pb2p1p/5P1P/1R6/2K5/7b b - -,34,561,18854,277457,9514087,141493176 -k7/3n4/8/6R1/1K6/2p5/7P/3b4 b - -,17,360,5797,110911,1843609,33707036 -1nb4k/4p1r1/5pp1/1PBp3p/2p2PPP/1p2P1K1/3bq1BN/1NR2R2 b - -,37,1012,37737,1041440,39059061,1092881681 -7r/r3k2p/4n3/1p3pp1/P5P1/7P/4K2R/8 b - -,34,479,16018,244014,7903507,125795564 -5r2/k7/4p1p1/p6p/P6P/3pnP2/6R1/1Rr1BK2 w - -,2,70,1561,50061,1172814,36007445 -8/k7/4P3/8/6B1/2Q5/6P1/1Kb5 b - -,12,437,4224,138151,1386199,44070885 -8/6k1/3P1n2/5P2/p1b1N1p1/P3K3/r1RN4/4b3 w - -,19,590,12290,352809,7700481,214939569 -1k6/4N3/6P1/4N2n/1b6/8/p7/7K w - -,16,277,4154,81048,1247918,25699052 -4N2k/8/8/2P5/B7/8/K7/8 b - -,2,32,129,2245,8944,162342 -8/r5P1/1k3P2/8/6Kp/2B5/4Rq2/8 b - -,34,723,22110,493584,15215520,356352505 -8/5n2/3p4/3Bk1N1/8/8/2K5/8 w - -,26,212,4679,42778,855696,8342315 -6b1/1r2k3/1p5N/P2PPP2/1n4P1/6BK/b1B5/6R1 w - -,30,605,17789,391718,11430001,267370325 -6r1/5b1k/1p1B2RP/1Pnp1p2/6N1/1p1p3K/6B1/8 b - -,25,651,14816,396193,9102194,246471506 -r7/1pp3r1/pk1P4/1P2npbp/5p1P/N1K2PP1/P7/4nbN1 w - -,16,690,11027,464014,7657451,314617527 -2b1kr2/r2pbp1p/2n3N1/QPP2P2/1P1p4/4pP2/3NK1Bq/R3R3 b - -,42,1533,60278,2161646,82719713,2933385214 -4B1nr/pppr1p1p/6bq/2b1k3/1n1pPpp1/3P1PPP/P1P1Q3/RNB2KR1 b - -,38,1133,40756,1218777,43779285,1327851164 -2bqk2r/1p1p1pbp/r1n1p3/p1P2Pp1/3p4/5P1N/PP2K1BP/RNBQR3 w k -,33,1084,37048,1201831,42726174,1383772378 -rq2kb1r/p1pp1p1p/b6n/np2p1B1/2QP4/6P1/PPP1PP1P/RN1K1BNR w kq -,45,1275,54714,1611221,66437861,2021875429 -rnb1kbr1/pp1ppppp/2p4n/6Q1/3PPP2/2q5/P1P3PP/RNB1KBNR w KQq -,6,185,6365,193007,6688629,204494861 -2k3r1/5R2/2n1N3/3pbP2/8/8/8/3K1n2 w - -,22,727,14653,451588,8991123,265062186 -8/k7/1b2P3/8/6B1/2Q5/2K3P1/8 w - -,38,377,13032,134554,4470448,46271950 -1n1r2k1/3b2br/6Rp/p1p5/7p/N3Pp2/5K2/6RB w - -,32,683,20532,525798,15383867,430601176 -8/8/4K1pP/5nkP/2r5/2p2p2/8/8 b - -,27,160,4135,25782,651543,4730068 -2N3n1/2k5/6P1/b7/8/p4N2/1r6/7K w - -,14,396,4843,125909,1602532,41276598 -3b2k1/8/b7/8/8/B2p2p1/6P1/K7 b - -,16,151,2599,27076,497637,5516097 -2B5/2r1b3/7k/3r4/4b3/2p5/1n3n2/5K2 b - -,54,539,27827,278835,13881673,141181079 -5R2/1k2n3/3P1N2/1p2K3/1p1R3P/1P6/6q1/7r b - -,40,932,33579,804650,27727991,664296126 -k7/1r6/8/5K2/2p5/2PN4/8/8 b - -,17,239,3751,46617,723196,8505951 -b3k3/8/1N4r1/4bnp1/pBp2P2/4p1PB/8/1K1R4 b - -,39,1389,49768,1650240,56638471,1797417391 -4k3/8/7P/Pb2P1B1/6P1/8/3K4/8 w - -,15,168,2672,31268,507922,6077039 -2Bk4/2N4N/Q4b2/P2p2P1/5R1p/2r1p2P/4K1R1/8 w - -,46,764,33387,583797,25331589,445558337 -r4b2/1b1npk1r/p2p4/P1pq3p/3P1N2/4P1P1/K2Q1PP1/R2N1B1R w - -,5,164,5869,200833,7370068,259322893 -8/r7/8/1p6/4k1p1/4n3/8/1K4R1 b - -,30,303,7540,93462,2247977,30744137 -r1b2r2/1p1p2k1/nb1q4/pp2p1p1/P1B4p/2B1npPK/RQP4P/1N4NR w - -,30,1545,45221,2206800,66434953,3121499676 -2b5/r3nk2/1n1P4/NP3Pp1/p3K3/P7/2r2N2/2R1b3 w - -,22,915,19286,752939,16216458,608173441 -8/1k6/1P6/5p1p/1b1P4/8/N6r/B4K2 w - -,7,172,1663,38394,423672,9365165 -4kbr1/2p1pp2/r1nqb1p1/pp5n/1PPp4/3PPP1P/PB1N2BR/1R1QK1N1 w - -,31,1274,39063,1610030,50140451,2068777209 -8/6r1/8/1p6/4k1p1/4n3/8/K4Rr1 w - -,8,227,2290,64038,749574,20958996 -r1bq1bn1/pppppkp1/2n3r1/5p1p/PP2P3/B1P2N2/3P1PPP/RN1QKBR1 b Q -,31,891,24888,734610,21113517,642198009 -2R5/2b2b2/8/4k3/8/8/5r2/4n1K1 b - -,38,375,12600,159834,5126867,66256704 -rnbq2n1/1pppk2r/p3pb1p/1N3p2/8/3PPQ1N/PPPB1PPP/1R1K1B1R b - -,28,1134,32305,1301504,37602368,1508787729 -8/8/1k6/1p5r/8/4n1p1/K7/8 w - -,5,145,642,17630,80389,2153406 -5bk1/5b1r/1p1p2Bp/Ppn2RpP/3P2p1/1R2K3/2P1Q2N/8 b - -,24,984,22261,901229,20363602,815150042 -k7/8/p1b5/8/8/8/4K3/3rB3 b - -,25,246,5930,61353,1470365,16839032 -q7/6r1/3b1P1k/8/1pP1R1P1/3Kn3/8/1B6 b - -,50,797,34141,576795,22056361,396949238 -8/k6b/4Rn2/8/1K6/8/7P/2b5 w - -,21,460,8482,188869,3375080,76476376 -8/1B3n1n/8/Pp1p1P1p/1k2R3/1P5P/2p4b/2K2RN1 b - -,7,205,4184,114143,2330802,63224585 -3r4/3n1k2/p2p4/P1pbp3/R4Nrp/4PP2/B2K1QP1/3N3R b - -,32,1216,39607,1489768,47877462,1802138954 -2b4k/5n2/1QP2r2/p2p1p2/P4PPp/1P1N3P/5n2/R1K5 w - -,30,709,20239,485957,14231831,344312903 -8/8/1k2p3/1N2P2p/K3P2P/8/2B5/8 b - -,4,54,223,3073,13855,202747 -8/8/8/2R5/1k5n/2b5/K7/8 b - -,15,204,2845,40805,622440,9223375 -rnbqkbnr/p2ppp1p/8/1pp3p1/P3P3/1P4P1/R1PP1P1P/1NBQKBNR w Kkq -,34,839,28222,742298,25100662,702252361 -r1k5/1p3pnp/3pp2b/4Q2P/P1p3BB/R2P1n2/2K1P3/6R1 w - -,53,1543,68735,1958380,84237046,2389437661 -3k2b1/6Rr/p2p1P1p/P6P/1b6/3p4/3R2P1/5K2 b - -,16,373,7034,151357,3109575,65692861 -1k6/3B4/4p3/4P2p/4P2P/K7/7N/8 w - -,14,59,911,4346,69277,341456 -6r1/2p5/1p5N/1p2np2/5P1K/2k5/8/8 b - -,33,225,6326,48880,1267227,11097394 -1N6/8/P4RP1/3B2rk/7P/3p4/K5N1/2b5 w - -,32,478,13579,234394,6723772,123563447 -rnb2bnr/2p1p3/p2pk1qQ/1pP2p2/2N5/4P2P/PP1P1PP1/R1B1KBNR b KQ -,24,817,22759,775616,22959346,782424152 -R7/2k1b3/8/p4p2/3Np2p/R1r4B/5P1P/1r2K3 w - -,2,82,2296,74534,2103560,65195216 -r1q1k2r/p1p2pbp/b2p3n/1p1Qp3/3PP3/Pn2B1PN/1PP2P1P/RN1K1B1R b kq -,34,1282,38044,1475021,45158472,1771880718 -8/8/1k6/8/6pp/1K6/8/r6b w - -,5,145,735,20956,108661,3074197 -6b1/1r2k3/1p5N/P2PPP2/Bn4P1/6BK/8/1b3R2 b - -,23,728,15801,482185,11054093,332113971 -4n3/R7/P1p1P3/5kp1/4r3/1PB5/2NK4/b6N b - -,24,645,13941,375337,8229836,220572995 -6r1/2R5/7k/3q4/n6K/8/6B1/1b6 b - -,50,934,39776,734321,30242210,557907296 -4r3/5P2/2P5/6k1/1p2B1P1/6b1/5K2/6R1 w - -,7,157,4024,81503,2103695,40934165 -1n1rkbr1/3bN3/3pp2p/qpp3p1/1nQ1P2P/P1PP4/1P2N1P1/R1BB1K1R b - -,31,1307,41463,1749150,56037855,2360270858 -4rbkr/2n1p2p/3P2p1/p7/2pQ1P1P/P1N1P3/4K2R/1RB2BN1 w - -,49,872,42617,828709,39740491,817764368 -8/b2n1k2/p2p4/P2P4/P1p4Q/2N2KB1/4B2R/8 w - -,36,570,21103,299617,11643913,162587155 -k7/8/7P/rb6/5b2/5N2/4pK2/8 w - -,12,359,3549,113619,1149731,37697620 -b4b1n/3k2rR/P1pB1P2/6p1/p1Pp1QP1/N3p1P1/R2PB3/1N3K2 b - -,16,633,11771,467842,9069299,360044271 -k7/8/3K4/7r/8/2P5/8/8 w - -,6,99,673,10961,70744,1162259 -rn4r1/p2kpn1p/B1p2b2/4Bp2/3P4/5N2/PP2KPPP/R1r4R w - -,35,1407,48985,1804803,63325550,2220749302 -1nb1k1nr/6bp/p2p1q2/p1pPp3/P1P3p1/Rr3P2/1P1NP1BP/2B1K1NR w Kk -,19,783,16055,631131,13857499,526016397 -2k2q2/2P2rb1/2r1b3/1p1pP3/1p6/7B/5BPn/4K3 b - -,40,604,23621,362345,14501179,230629399 -bk6/b7/7p/2P4P/3Kp3/P7/7N/5r2 w - -,8,165,1505,32415,322005,7215607 -1b2b3/4P1r1/8/7P/2P1k3/r7/3RpK2/8 b - -,45,614,23058,331202,12347165,187781588 -3R4/rpp3r1/1kn3P1/1p3p1p/5p2/P1K2PPb/8/1N2n1N1 b - -,31,673,20901,421426,13037819,261668591 -2r5/6kp/p4n2/p1pP2P1/P1nN4/1r1B3P/5N2/2bK3R b - -,46,1323,54243,1499634,60014981,1629603125 -r4b2/2p1p1r1/2Pkb1p1/p1q2p2/p1Pp1P2/B2P1P1P/P2N2B1/4KRNR b - -,19,265,5089,82325,1838112,32987100 -6B1/P7/4N2k/8/1p4K1/7p/8/2r5 b - -,17,302,4860,95961,1551954,33055943 -1r1k1b1N/pn1b2rp/2p5/3ppP1p/1p1P1P1P/6PR/2P1B3/1K4B1 w - -,26,775,19453,592841,14733674,455004592 -rnbqkbnr/ppppppp1/7p/8/8/4P2N/PPPP1PPP/RNBQKB1R b KQkq -,19,550,11624,357283,8387800,268057495 -B7/2kN4/7B/p5P1/1p1K1R2/P6p/1P2P3/8 w - -,38,298,10870,83465,2957804,24039111 -8/3k1p1p/6r1/p2rp1R1/1b6/pRPNBB1b/3K1P1P/8 w - -,31,1186,39360,1391693,48830548,1654821537 -1k6/8/Pp4r1/3R4/2P1B3/5Np1/8/3K4 w - -,33,446,14559,200985,6279483,90693740 -bk4r1/3r2N1/p1p1R1P1/Pp1n3P/1P6/1P3B1P/8/1rB1K3 w - -,25,764,18450,559745,13819368,418944394 -5k2/2B5/6r1/Rp1ppK2/8/1n4Pr/1p4NP/1N4b1 b - -,40,847,30439,689748,24444089,575812639 -8/1K6/1P3k2/8/8/8/8/8 b - -,8,56,432,2487,16989,112986 -8/7r/8/1pk5/8/6p1/6n1/1K3R2 w - -,17,388,6514,142322,2308547,49584030 -6bB/2n2k2/7p/2r5/6K1/1P1pp2R/8/R6B b - -,27,913,22708,767702,19161665,647793153 -2b1r3/2Np3k/8/pr3p2/P1P2PPp/1P1P3P/2QKN3/R3n1n1 b - -,35,1079,35457,1028266,32427166,916350597 -7k/3bQn2/pp2p3/PPp1P2p/4B2P/4P3/4K3/4NN2 w - -,37,465,16151,195936,6790132,84327032 -2N5/7k/N2p4/1p3n2/P1PP1Q1p/1P3P2/7P/2K2BrR w - -,32,661,22416,428716,15168340,279274708 -4k3/1p6/5R1n/4rBp1/K3b3/2pp2P1/7P/1R4N1 b - -,24,762,18319,574308,14529429,447703830 -Rn6/p2k4/2ppp3/1pqPP3/1P4p1/2P5/3RBbPQ/2K5 b - -,25,825,19343,632994,14992365,489061732 -2N4k/7r/N2p4/1p3nP1/P1P4p/1P1P1P2/3B3P/2KQqB1R b - -,34,1002,32100,979404,30785461,974965701 -k5nr/4r3/8/np1P2Pp/1p1Pq2P/1P1N1N2/6K1/6RR w - -,23,837,18747,709234,16708925,635249332 -Bnbqk3/2pppp1r/pp4p1/7p/PP4Q1/B1b1P1PP/3PKP2/RN4NR b - -,28,1022,27294,988395,26364933,953319366 -2r3k1/7r/4n3/1R5p/p6p/3pPB2/8/b5K1 w - -,31,1261,33230,1245268,30158737,1089143546 -1nbr2k1/6br/1p3R1p/p1P5/7p/N3Pp2/5K2/6RB b - -,26,859,21792,675743,18322529,548856919 -8/8/8/1k6/3R3n/1K6/8/6b1 w - -,19,254,4774,71642,1289844,20513438 -1r1k3N/pn1b2rp/2pb4/3ppP1p/1p1P1P1P/2P3PR/4B2B/1K6 b - -,32,714,22230,476999,14935073,318477808 -r1b2r2/3k2p1/2n3p1/pP3p2/3BP2P/1P1P3R/2P1N3/Q3K1n1 w - -,42,1256,49324,1412942,53460187,1518672410 -r4bkr/p3p1pp/n2P1Q2/2p5/5P1P/P2b4/1N2P2R/R1B1KBN1 w - -,39,838,32906,714319,28471658,632153896 -rn2kbr1/pb2ppp1/1Nq5/2p4p/2PP1P2/P3P3/RP2K1Pn/2BQ2NR b q -,35,995,35437,1051159,37629671,1151913429 -r1b1kbnr/1p1p3p/6p1/p1p1np2/q4B2/P2PP3/1PPQ1PPP/R3KBNR w KQkq -,32,1179,35953,1328268,41111810,1517802854 -r2B1qr1/p1nbbk1p/1p2p1pn/2p2p2/4P2P/PP3P1N/1R1P1Q2/2B1KB1R b K -,34,1151,38390,1372713,46389484,1708298765 -1nbqkb1r/1ppppppp/r4n2/p7/3P4/7P/PPPQPPP1/RNB1KBNR w KQk -,28,726,22415,609289,20025881,564184168 -6r1/7p/2K4P/6kP/2p4n/5p2/R7/8 b - -,20,398,8583,154896,3328034,56249549 -8/8/7B/R1K1P1P1/4qk2/P7/1p6/8 w - -,13,360,4727,129748,1922279,52817465 -2b2kr1/p7/B2ppn1b/Pr1PP1N1/6Pp/R1p4P/2P5/1N1QBK1R w - -,35,1024,37907,1097925,41342197,1208040412 -r1k2bn1/p1r5/1PB2p1B/P1p1p2P/2P5/2R2N2/8/4K1NR w - -,41,764,30408,575088,22476211,438779893 -8/7b/B1P1P3/P1k3Nn/7p/K1p5/6P1/3N2R1 b - -,17,440,7690,208742,3714093,104486232 -bN5b/8/5P2/5kP1/N1P5/Np1R2p1/4K3/8 b - -,18,511,8677,242909,4309117,119037040 -1n1qkb1r/r2b2np/pp2pp2/1Npp4/2B2pP1/1PPPP2P/P2B1QK1/R5NR b k -,27,892,24633,845428,24744738,866263086 -r4b2/2n1r3/3k2pp/P3p3/6P1/R1PPPBnP/1B1Nb3/4K3 w - -,26,824,21597,697477,18277943,601047697 -2Bb4/2r5/7k/8/4b3/2pr4/1n2Kn2/8 b - -,48,433,20362,191207,8898603,85553053 -1R5k/3b4/5PP1/2p4P/5K2/8/8/8 b - -,2,40,167,3519,28882,593203 -1n2rQk1/7p/rpb1pb2/p4N2/P1P1pP1p/5n2/4PK2/4RBBR b - -,2,46,1698,38073,1357065,31502946 -1rbqkb1r/1p1p2Qp/p1p2n2/1B2p3/3P1p1P/BPP1P3/P2K1PP1/RN4NR b k -,30,1304,34568,1448061,38794644,1579267876 -rn5k/p2p2q1/1pp1p3/1R3pp1/P4P2/N7/3KQPb1/2B3N1 w - -,36,1057,35567,1016100,34211609,969209353 -2b5/3N1k2/1n1P1n2/1PN2P2/p5p1/P1RK4/r7/4b3 w - -,17,520,10095,307925,6268262,189422115 -1K6/7R/6b1/6q1/P5kB/8/8/8 b - -,29,507,15414,280088,8358401,157257828 -1n6/3bK3/5B2/1kp5/8/8/8/6q1 b - -,35,408,14407,171151,6012160,66273532 -8/8/2P1k3/5p1p/8/8/4N1K1/B7 b - -,6,130,953,19254,136906,2722446 -k7/8/8/8/2pK4/2P1rN2/6r1/8 w - -,11,292,2707,68578,677566,17317048 -r1r3n1/1p5k/1PP1p1p1/5p1p/R4P1P/6b1/2K5/7b b - -,30,556,17763,303305,10094177,163756332 -8/5k2/4R3/2PP4/1K2p3/6p1/8/2r5 b - -,16,269,4244,70169,1134633,18610020 -1r2kbr1/p1n1p1pp/8/1pp2p2/1Q4nP/2PpR2K/PB1N4/RN3B2 b - -,30,1022,28591,971848,26822702,921900903 -1B6/B2n1k2/8/5P1P/2pK4/R2n1p2/8/7r w - -,23,739,17589,514325,12537579,345094240 -8/B4bk1/8/8/1b3K2/6p1/6P1/3n4 w - -,14,373,4557,116799,1396590,34845553 -1K5k/7N/8/1P6/r7/5n2/8/8 b - -,25,180,4033,36973,779992,7480116 -6r1/1k3P2/2n5/6N1/3p4/6b1/7n/3K4 b - -,36,564,17470,290678,8263633,141839038 -8/q7/5k2/p2r3r/PP2p1P1/1K1P1N2/2R1p1B1/1n2N3 w - -,30,1319,36032,1514645,39420646,1618758594 -rnbqk1n1/1ppp3r/p3pp1p/6Q1/1b6/2N1P2N/PPPP1PPP/1RBK1B1R w q -,42,1140,46424,1225194,48947342,1300260731 -2b2r2/1rNp3k/8/p1P2p2/P4PPp/1P1n3P/N1QK4/1R4n1 w - -,30,928,28001,820571,25269409,731673180 -N4b2/1r6/5Pk1/8/qpP3P1/4B3/B3K3/n4R2 b - -,33,1007,32194,891351,28807351,760006631 -rnkq4/p4r2/b1p3pp/1p3p2/1P2P1P1/1PK2pnP/P2PN1R1/R1B2B2 w - -,22,941,19742,756455,17111032,621764247 -4k3/K7/p6N/p7/r7/8/8/N7 b - -,14,149,2457,28218,473135,5732811 -8/k7/B3p3/2K1P2p/4P2P/8/3N4/8 b - -,3,48,139,2134,8160,126113 -rnk5/p5r1/b1p3p1/1p3p1p/1P2P1P1/1P3pRP/PB1KN3/R4B2 w - -,35,744,24278,504502,16254689,340017080 -2k4n/8/8/8/2K5/8/8/7r b - -,20,144,3055,20305,436142,2582304 -7R/4N2b/k4P1N/6r1/2p2K2/2P5/3r4/8 w - -,22,780,15253,483611,9916712,296763160 -2b5/6r1/rp1b2N1/p1k2p2/PpPpP3/3Q1PqP/3PK3/RN3B1R w - -,24,886,19692,724429,17275655,635726225 -6b1/3k4/4R3/N7/p2p1p2/P2P1K2/4r1N1/1r6 w - -,24,741,15386,448358,9321047,265071917 -8/k7/8/8/B3K3/6p1/1r1b4/1N6 w - -,16,363,5668,134122,2092218,49528278 -1r2kbr1/p3p1pp/n4p1n/1pp5/1QN3PP/2PpR3/PB3K2/RN3B2 b - -,22,810,17678,648253,14883281,545212958 -1n3k2/BP6/b7/4pP2/2pP3P/1n3pr1/5K2/7R w - -,20,488,8964,219378,4105702,101166671 -2b1rb2/3k1r2/Q4ppp/2P1pPBP/1np1p3/NR3N2/P2P4/1R2K3 b - -,29,1167,27200,1113820,27138236,1118535867 -8/2kb3r/p4Q2/1p1KP3/2p2ppP/1PPR4/4N3/RN6 b - -,21,794,15179,562240,10830588,398003306 -1b6/6r1/2k4p/5p1P/P1n5/2BP4/3KN3/5R2 w - -,5,176,4905,146003,3910143,107959174 -6n1/3r4/3k1p1p/1B4rP/P4PR1/3Pb3/2NB3K/8 b - -,32,858,25242,686721,19350000,531048091 -5N1k/5n2/1N1pQ3/4r3/P1pP3p/1P3P2/1K5P/5B1R b - -,21,835,14780,582895,9760450,382136552 -8/r7/8/1k6/pN1P4/P4K2/2b4r/2R5 b - -,32,582,18408,351222,10616103,205566607 -n1k1qQ2/4p3/r2p3b/3P1bpp/ppP3P1/PP2P2P/3NKP2/2R1NBR1 w - -,36,1043,36054,1077115,37817626,1157399369 -1nbq1k2/3ppp1r/6p1/1pp1b2p/P4PP1/Bp1PP2P/6B1/RN1K2NR w - -,30,1058,31709,1099933,33351902,1153581958 -8/4R3/R7/2p2K2/2P5/2q5/3k4/8 w - -,34,720,17248,363943,8555617,178786895 -3N4/3k4/3r4/2Qn3p/7P/3RB3/3K4/8 w - -,36,534,19538,263921,9792133,145299770 -r1b2b1r/6kp/4P1p1/pp1p1p2/PQq5/2p3PR/R2B1PP1/3KNB2 b - -,37,1347,43965,1615658,54108903,2009912024 -Q1b2r2/q3b1k1/pp2p3/1Pp1P2p/P1K1B2P/1n6/2PNP1NB/3R4 b - -,34,1197,38974,1387642,43651256,1558929210 -q2r4/3k4/3N3n/1QP1p3/2PP1p1p/5PP1/1K2R3/R7 b - -,4,203,5223,229959,6243951,262225942 -1n1rkbr1/3bN3/1n1pp2p/qpp3p1/2Q1P2P/P1PP4/1P2N1P1/1RBB1K1R w - -,42,1291,54224,1707683,71201771,2289366876 -r1bqkbnr/pppppppp/2n5/8/3P4/2N5/PPP1PPPP/R1BQKBNR b KQkq -,22,637,15262,463750,11954763,378782596 -3N2k1/7R/8/Pp1pP1BP/8/1b1pP3/3K2P1/8 w - -,28,239,6319,52000,1321404,11604346 -rnb1qb1r/2pppk2/pp6/5ppp/P1PP4/3nP3/NPQ2PPP/R1B1KBNR w KQ -,5,149,4437,135716,4146658,129769653 -1r1k1bn1/pb2p2r/np6/P1pP2pQ/3Pp2P/BP3N2/5PP1/R1N2K1R w - -,34,975,35028,1014451,37684902,1107976319 -3n4/5k2/p2p4/P2PB3/P1p4Q/2N2K2/4Bb2/4R3 b - -,17,765,11252,478933,6941319,289895282 -3r2n1/8/2B2p1p/2k3rP/P4P2/2BP4/2N2b1K/6R1 b - -,31,1107,30461,1007637,27189642,853081835 -2n2k2/3bp3/N3P3/p6P/4K3/1Q3P1p/2r5/4R1rn b - -,37,1142,39744,1217006,40592422,1244071070 -8/8/1k6/1p6/8/K3n1p1/7r/8 b - -,31,78,2121,8544,229192,935173 -1n1qkb1r/1bp2ppp/r7/1p2B2n/p1pP4/1P3P1P/P3P1P1/RNQ1KBNR w KQk -,36,1764,58711,2719707,89089791,4001579772 -2N2R2/5k2/pK3N2/p7/P7/N7/8/2r2n2 b - -,4,91,1490,35034,627619,15726193 -3rkbr1/2n1pp1p/5npB/ppP5/PP6/1RP4b/5P1P/2NK1BqR w - -,5,219,4548,194315,4369931,185683528 -1nb2b2/r7/1P4k1/pP2B3/2P1P1p1/1N4P1/1R3KBP/4r2R b - -,40,1184,43419,1351160,46871251,1501466893 -b3nbr1/k4Bp1/4p3/3p3p/P2P4/5nQ1/KR6/8 b - -,24,953,21723,813569,19487652,703375778 -8/6p1/7q/8/2K3n1/2R2bk1/8/8 w - -,13,410,5597,184330,2633591,89746359 -6n1/5rr1/5p1p/2k3PP/P7/2BP1P2/2N2b1K/6RB b - -,23,691,16414,462483,11647446,316870873 -2B1k3/2Q4N/P5P1/3p4/3N4/1R2p1pP/4K3/1r6 b - -,10,412,4275,173238,1872010,74457963 -8/2p5/1pn2N2/1pk2pK1/5P2/8/8/8 b - -,13,166,1956,20988,259410,2676981 -8/1qk1r3/p3pnp1/7p/P1pP3P/4rP2/3R1KB1/2B1R3 w - -,24,1076,23723,1001391,23293069,941242169 -6nr/2kB4/3N4/pbP1p3/2PPqp1p/4RPP1/QK2R3/8 w - -,45,1332,53426,1633892,65135791,2038252484 -2rk3b/R6p/7P/3p4/8/p7/1p4K1/8 w - -,20,399,6759,157631,2499509,63727285 -8/8/6n1/6R1/1k6/8/Kb6/8 w - -,14,219,3159,48320,716652,11274020 -r1k5/pb1n2r1/2p3p1/1p3p1P/1P2P2R/1PB4P/P2KN3/4rB2 b - -,28,622,17999,429276,12784351,316576972 -r1bNk3/p2p1r2/n6p/1B1pp1pP/1b3p2/P1B1P2R/Q1P3P1/R3K1N1 b Qq -,26,1035,26244,1071124,27327604,1132154695 -rn1qkb1r/1bp1pppp/5n2/pp1p2B1/2PP4/5P1P/PP1QP1P1/RN2KBNR b KQk -,29,924,28078,920978,29083599,969862713 -r1b1kb1r/pp1ppP1p/6pn/q2p4/n4PP1/P1P4B/1PNQK2P/RNB4R b k -,3,87,2571,73516,2300762,70205191 -1k6/8/1P6/2b2p1p/3P4/8/1N5r/B4K2 w - -,9,190,1748,37008,414384,8631689 -2b4r/R7/5P1k/2p2P2/2R4P/6Pp/7K/r7 b - -,24,589,14350,343882,8833468,210528029 -r7/2P2P2/8/6k1/1p2B1P1/6b1/4K3/6R1 b - -,28,966,23076,755103,16503572,534262994 -7b/8/1p3k2/PP3N2/2B1K3/4b3/1R6/8 w - -,33,434,13307,178246,5165483,75053042 -4B2k/8/4P1R1/1p3P1K/8/1n6/7B/8 w - -,26,189,5129,35260,964944,7275615 -2N2k2/4qr2/Np1pb2n/B3Q3/P1P2pPp/1P1PPP2/3K3P/4RB1R b - -,29,1357,39574,1763958,52599158,2268704256 -rnbqk2r/p2pbpp1/1pp1pn1p/P7/3N4/3PP3/1PP2PPP/RNBQKB1R w KQkq -,36,1078,37949,1157191,41140415,1278970378 -rn1k3r/pb1pb2p/2p1p1q1/1N5n/P1P5/1P1p2Nn/R2P2KR/1QB5 b - -,43,975,40584,995729,40412058,1064506885 -k2B4/8/1n5p/3p4/b7/3p4/7n/N5K1 w - -,12,219,2983,56944,826785,16295130 -1r1r1bk1/1p2p3/1P3ppn/1Pp4p/1n1P1P1P/1R6/3K4/R2b4 b - -,33,861,28710,671269,22502907,505418045 -8/3P1k2/p6Q/P7/N7/2p4B/2R1p3/4K3 w - -,39,114,4232,16787,611243,3183131 -8/2k5/q6R/2PP4/4p2r/1K3Ppp/6R1/8 b - -,34,733,20740,450219,12472237,271970768 -1r2kb1r/4p1pp/2p2p2/p1p1Pn1n/2PP1P1q/8/2R1KN1P/1NB2B1R b - -,35,863,30783,763846,27429480,698746580 -r1b1kb1r/pp1pp1pp/n1p2p1Q/8/3PPP2/q2KB3/2P3PP/RN3BNR w q -,7,194,5602,152504,4707858,132049061 -rnbqkbnr/p1pppppp/8/1p6/6P1/7B/PPPPPP1P/RNBQK1NR b KQkq -,21,399,9231,198188,5015655,119034029 -rn1qkbnr/p1p1pp1p/4b3/1p1p2p1/2P5/NQ2P3/PP1P1PPP/R1B1KBNR b KQkq -,29,864,25107,775794,23249302,738996969 -1N1Q4/4p2k/3r1P2/p1K4P/2n5/1r5p/R7/3b3n w - -,29,1103,29813,1091535,29865074,1069694988 -8/r1k4b/np5N/6Q1/3PPPPp/PP6/b4B1K/3Bb2R w - -,36,747,26199,591438,20688936,494878791 -rnb1kb2/p2ppppr/1pp2n1p/3P3P/5q2/P1N5/1PP1PPPR/R1BQKBN1 b Qq -,39,1078,38592,1162500,40117094,1286826888 -8/rkp1r3/5pp1/p2PpP1p/P1P1PqP1/2N1Q2B/1P1K2R1/R1B5 w - -,26,743,21513,587292,18145715,491644075 -6n1/6p1/7q/5R2/4b1k1/1K6/8/8 b - -,38,652,22002,348721,11608619,175918895 -3k2b1/2p1r3/3N4/p4pbr/p1Pp2R1/P2P1P2/2K5/B4qN1 w - -,22,943,17680,733631,14386718,588404908 -2kN4/8/3r4/1Q1n3p/7P/3RB3/2K5/8 b - -,19,745,12414,506864,8008927,325847693 -8/6k1/n7/rb3pP1/1pRp3p/1P5P/8/2K4n w - -,14,309,4406,105414,1469943,36422105 -r4br1/8/k1p2npp/Ppn1p3/P7/2PPP1qP/4bPQ1/RNB1KB2 w Q -,24,1036,25308,1095789,27999381,1209827199 -r4b1N/q1k5/1p1p1n2/1b1Pp1pp/1p2np2/2B2PPB/2R5/4K1R1 b - -,43,1247,45864,1314619,51084386,1460217519 -5k2/1BN5/6P1/1P6/8/p7/b4B2/5KR1 b - -,10,285,3117,90329,1024593,30472007 -4rR2/8/4k3/8/3B1P2/7p/8/2NR1K2 b - -,11,343,4220,135505,1799467,59247999 -8/5B2/8/6k1/8/6K1/8/3n4 w - -,13,111,1549,15421,206318,2158321 -4k3/7p/2b4P/3pb3/p1p5/1B3Rp1/3Kr3/7r w - -,1,36,618,19092,336460,9984188 -2k5/8/8/p3r3/8/1b5K/8/8 w - -,5,140,774,21380,105440,2885304 -rnbq1bnr/2pk2p1/1p1p1p2/pN2p2p/3P3P/2P1P3/PP3PP1/R1BQKBNR b Q -,26,962,25534,944902,25812452,959704886 -2b5/6r1/rp1b2N1/p1k2p2/PpPpP3/3Q1q1P/3P4/RN2KBR1 b - -,41,953,37293,941740,36019488,967679866 -8/8/6P1/8/2b4P/2k5/8/3K4 b - -,16,73,1091,6579,97531,769922 -1b5r/3b2kp/8/pB1pp1rP/2pP1Pp1/2p5/3R3B/3K4 w - -,23,644,14427,408379,9116751,260854290 -4k3/1p5B/5R1n/3r2p1/3p4/KRpb2P1/7P/6N1 b - -,30,985,25586,807684,20401293,633560197 -1B6/3n1k2/1r6/5P1P/2KB1n2/5p2/8/8 b - -,32,638,18677,351957,9676815,182642936 -4N3/8/4N2k/p2r1p2/P1K2P2/8/5b2/8 b - -,22,289,5714,73697,1415737,19169319 -5B1r/2bb1k1p/8/pB1ppr2/2pP1PpP/2p5/2K3RB/8 b - -,28,732,20620,532585,15131064,389225805 -1n3k2/q7/2rP4/3K1P1p/1b6/8/1R6/8 w - -,15,645,9270,352764,4986167,184258598 -8/6k1/n7/rb3pP1/1pRp3p/1P4nP/8/2K5 b - -,25,316,8233,111027,2980069,40447031 -1r6/8/8/k7/N2P1K2/P2R4/8/6r1 w - -,18,539,9750,264438,4977685,127743287 -1n6/B6k/bP3rR1/4p3/2pp1P1P/4Pp2/3n4/4R1K1 w - -,24,565,13444,321732,7808505,190859955 -1b4r1/5b2/rpk3N1/p4p2/PpP1P3/2RB2RP/3P4/1N2K3 b - -,30,802,22842,630254,18218858,514003152 -r1q1kr2/p1p2pbp/b2p3n/1p2p3/2QPP3/P3B1PN/1PP2P1P/nN1K1B1R w q -,41,1106,42760,1224115,46473183,1400038166 -5k2/2b5/1p5N/PP6/2B5/5K2/6R1/2b5 b - -,17,547,9555,283863,5003619,143966343 -5r2/2b1k3/B5p1/p3p2p/P3PP1P/1Q6/2rp1K1R/2RN2N1 w - -,47,1415,53421,1503730,56599029,1542277829 -7k/8/1P4P1/p4r2/8/2K5/6B1/1R6 w - -,29,434,10565,157724,3778645,56072359 -1b3k2/8/1p2B2N/PP6/6K1/2R5/1b6/8 w - -,34,534,16641,285285,8431246,147743351 -6nr/1p3k1p/5p1b/pqppp1p1/1PN1P1P1/B1P2P1P/P2PK1BR/3RQ1N1 b - -,25,593,14848,398043,10212371,293181188 -8/2Pk4/n4bp1/6rp/3pQ2P/6B1/8/2RK4 w - -,44,702,28030,514113,19715646,383263235 -7k/3R4/7P/3B1bn1/4b3/6K1/8/8 b - -,18,423,8302,199421,3981980,93632723 -8/6B1/1K6/4P1k1/P3q3/8/4bR2/8 w - -,20,569,10260,285473,5280720,144986991 -6nr/P1p1p3/n3br1k/bpP1P1q1/6pP/N5P1/P1B1pPK1/R5NR b - -,42,1272,53461,1630260,69613559,2151245773 -1N4B1/8/P5P1/4r2k/7P/3p4/K5N1/2b2R2 b - -,24,634,13416,356230,7444014,200420260 -8/2k5/2B5/1pq5/3p4/1p6/8/5K2 b - -,26,307,7692,84262,2139087,23104145 -1r2kb1r/p3pbpp/n4p2/1pp1Nn2/4p1PP/2PP4/PB6/RN1QKBR1 b Qk -,33,1105,35522,1216552,38472949,1334967986 -k2B4/Pq6/2n4p/3p4/8/3p1K2/4N3/3b1n2 b - -,37,367,12818,162012,5609613,77006608 -2B1k1n1/r1n2p2/2p3r1/1pbPp1q1/Pp3P1P/N1PPB3/2Q5/2R1K2R w K -,49,2220,99215,4425251,191463568,8427397678 -4rb2/2p1p1r1/2Pkb3/p1q2pp1/p1Pp1P2/B2P1P1P/P5B1/1N2KRNR w - -,15,288,4942,111469,2080687,52425712 -rnbqk1nr/ppppb2p/4p1p1/2P2p2/8/1P2PP2/P2P2PP/1RBQKBNR b Kkq -,24,624,16179,433591,11959057,332274636 -r1b3nQ/pppk1p1r/3pq2b/3P2pp/4PpnP/N1P2PPR/PP2K3/2R2BN1 b - -,33,944,29981,892116,28111139,860947660 -r7/2pr2P1/P3kn1p/P2p3P/3Pp1b1/1P1nK2R/1B3R2/1B6 b - -,37,1073,34879,995004,31650022,907464445 -3k4/8/8/2PBb3/4p3/2K1N3/8/8 w - -,5,90,1950,27716,585553,7814002 -1B6/1r1Nbr2/nP4k1/1b2P3/3K2pP/6P1/7R/4R3 b - -,39,1110,40231,1120300,39913978,1106850582 -8/R7/8/8/1k5n/8/K7/4b3 w - -,15,173,2800,40006,650486,10159857 -2n5/5k2/1P6/8/3P3P/8/3N2K1/7Q w - -,25,286,7815,78271,2237189,21543553 -8/p7/P6B/4k3/N2q3p/2K5/8/8 w - -,2,56,624,15699,199794,4781397 -br4r1/6B1/p6p/1N1B3k/1Pp1P3/3p4/P4b2/2RK4 w - -,31,1021,29732,975297,27577780,901174594 -8/7k/2R1P3/7p/4n3/8/2B4p/6K1 w - -,4,32,528,6391,122991,1587614 -8/B6Q/2R4P/8/1k1P4/8/8/bK6 w - -,34,245,8432,61809,2223430,19517090 -7r/2bbkP1p/8/pB1ppr2/2pP1PpP/2p3R1/2K4B/8 w - -,25,765,18980,558950,13808058,399959519 -3kr1b1/2p1b3/8/pN2ppP1/p1Pp3r/P2P1PR1/1BK5/4qBNR w - -,23,940,19497,764488,17011496,655208289 -8/p3N3/n3k1R1/8/3p1K2/5p2/3B4/4b1n1 b - -,3,85,1334,30453,514256,11747438 -1n4nr/p2r1B1p/1p5b/2p1B1kb/3pP1Pq/2QP1K1P/P1P5/RNR5 w - -,40,973,29771,774631,23890891,660754280 -8/2p5/1p4P1/1p3p2/1kn1bP1p/7K/8/r7 w - -,3,118,502,17802,126733,4086611 -r4n2/7p/2p2k1b/p6P/5pP1/8/K4B2/4R3 w - -,28,447,11426,205504,4949845,96755151 -5br1/1k6/1pR1R3/pP2pp2/B7/8/P4N1K/1n6 w - -,28,572,15767,356124,10168120,234314822 -rnb1kbnr/1p1pp2p/6p1/p1p2p2/P1P2P2/1q1P2P1/3BP2P/RNQ1KBNR b KQkq -,32,755,24397,623944,20474898,558801745 -8/6b1/5N1r/Pk2p3/1n5p/K1P1P3/1B6/1b6 w - -,15,418,5061,133804,1609522,42418189 -rn3bnr/pBp1pk1p/5p2/1p4p1/6b1/N3Q3/PP1P1PPP/R1B1K1NR b - -,28,1179,30344,1237350,31616814,1267752608 -1N6/8/3k4/4R3/4PK2/8/4Q3/2n5 b - -,5,123,824,27148,195888,6424545 -4q3/4bk1b/1pr1pnpr/p1pP3p/P2P1PPP/1QN3NR/1P1B2B1/R4K2 w - -,44,1292,57121,1773061,78003755,2498052309 -2bqkbnr/rpp1p2p/n2p4/5pp1/p1PP2P1/PP2P2P/1B3P2/RN1QKBNR b KQk -,25,703,18885,549873,15608368,472614722 -1rb1k1r1/p5b1/B2ppn2/6p1/P2P2Pp/2p2N1P/R1P1P3/1N1QBK1R w - -,34,966,32523,947558,31812362,941636711 -bk6/b7/7p/2P4P/4p3/P3K3/7N/4B1r1 b - -,18,251,5009,69089,1477251,21280321 -r7/pp3k1r/8/q1B1p2p/Pb3pp1/1PnPQ2N/1R2PPP1/1N2KBR1 b - -,42,994,40592,1034200,42152761,1132852669 -b3k1r1/6n1/1B6/1pn1N1p1/p1p2P2/b3p1P1/5N2/RK3BR1 b - -,30,970,30292,987735,31464036,1045173772 -rnbq1b1r/p4kp1/1p1pp3/1Ppn2pp/P2P1P1P/R7/2PKP3/RNBQ1BN1 b - -,36,972,34056,955645,32617173,955662615 -4n1kr/7b/1p2p1p1/p3b2p/qQ2BPPP/R1Bp4/1P1N3R/1N3K2 b - -,26,1084,28165,1195682,32082958,1369668737 -6k1/rp6/n4B2/2bpp3/P4r1N/1p4PK/7P/RN6 w - -,19,647,13388,429517,9678090,307074856 -k5nr/4r3/8/np1P2Pp/1p1P3P/RP1N1N2/5K2/q6R b - -,34,802,25167,606026,19213454,468462938 -bk4r1/3r2N1/p1p1R1P1/Pp5P/1P6/1Pn2B1P/8/1rB1K3 b - -,35,782,24712,578201,17815039,437900742 -rnbk4/1p1qbppr/2p1p2n/3p3p/Pp3N1P/3P1P2/2P1P3/RNBQKB1R b KQ -,30,844,25998,758588,24598491,738780682 -b3k3/n7/P7/2p5/2PpPN2/3Pb3/1p4Kn/8 w - -,10,243,2522,62701,622433,16313037 -r2k1br1/2p1p3/2n1b1p1/pPq2p2/p1Pp1P2/B2P1P1P/P2N1KB1/1R4NR b - -,30,768,22854,571531,17289248,434278875 -2n5/1r1B4/3k1pRp/5r1P/P7/3P4/2NB1bK1/8 w - -,34,1148,36933,1181842,37053255,1143053213 -R7/3K4/b5q1/P7/8/8/7k/8 b - -,34,344,10884,119345,3662421,44556648 -rn1k3r/p7/b1p3pp/qp3p2/1P2PpP1/1PNB2nP/P1KP1R2/R1B5 w - -,30,862,25044,747303,21634775,666180474 -3n2k1/8/4p1b1/4P2p/Qp2P2P/8/3K4/2N4B b - -,14,376,4858,129817,1754190,47753994 -k7/8/8/5K1r/8/2P5/8/8 w - -,6,102,646,10680,74536,1257616 -2r5/n3b1kr/6p1/p2P1p2/PPbp1P1p/B3P1Q1/5KPn/R5R1 b - -,45,1140,47840,1244067,50488584,1374189795 -2b1n3/N1b5/1p1k1n1p/3p1P2/P1Bppp2/1PP4P/5K2/R3B1NR b - -,24,553,12277,305016,6859751,179120302 -1B3b2/r7/nP4k1/NP2P3/2P3p1/4KBP1/2r4P/4Rb1R w - -,33,1269,37449,1355264,40113129,1395182990 -8/8/8/2k5/8/8/8/1b2nK2 w - -,4,72,368,6792,32474,597700 -b7/8/1k6/8/3K2p1/7p/8/2r5 b - -,30,106,3015,15940,443778,2262154 -k5n1/2P5/4KNq1/rp1P3p/1p2R2P/1P6/2R5/8 b - -,24,561,14048,350418,9209719,237694484 -rnbqk2r/1ppp1p1p/4p1pn/p3b3/2PPP1P1/7N/PP3PBP/RNBQK2R w KQkq -,36,1161,41648,1367780,48884281,1630769572 -2b5/r1n3k1/1P1P4/NP1n2p1/p3KpN1/P5P1/2rb4/5R2 b - -,42,1122,46838,1201455,49221791,1241861523 -rn1qk1nr/p1pp1pp1/bp5p/8/1b1p1PP1/2N5/PPPBP2P/R2QKBNR w KQkq -,25,897,22871,802938,21753775,758938528 -k7/8/5K2/8/2rP4/P6R/4N3/8 b - -,13,336,4899,117391,1761151,40747570 -n4kn1/3r4/5pr1/1P1Pp1R1/3B1P1P/2pP4/2Q2K2/1N5R b - -,26,1167,29215,1249019,31457182,1302270887 -1r4k1/1b6/1NQ3p1/pP1p1p2/P4PnP/3pR3/3BPN2/2R1KB2 w - -,49,986,47111,953063,44289104,908720827 -1R6/6k1/3Q4/3NP2p/Pp2Pb1P/5N2/5K2/8 w - -,46,422,16916,147602,5994615,54393250 -3R4/1k2n3/2qP1N2/1p2K3/1p5P/1P6/8/3R3r w - -,33,965,23837,725203,17341498,529259305 -3k4/8/1n6/1P1P1Q2/3Pn2P/2R5/4K3/1N6 b - -,16,615,8259,305392,3841847,137810427 -b7/1rb5/3K3k/8/8/2p5/1n6/2r4n w - -,6,204,851,31682,114091,4513684 -r2B1qr1/p1n1bk1p/1p2p1pn/1bp5/4Pp1P/PP3P1N/1R1P4/2B1KBQR w K -,32,1037,34142,1116454,38164636,1275871497 -8/6r1/p4P1p/P3k2P/1b4R1/1b1p2P1/3R4/4K3 b - -,33,460,11831,220679,5530632,114852010 -3krbb1/2p1p3/8/pN3pP1/p1Pp3r/P2P1P2/1BK3R1/4qBNR b - -,39,832,30360,706491,24521915,607239145 -rn2kb1r/1b1p3p/1PQ1p1pn/p4pq1/1P1PP2P/5N2/P4P2/RNB1KB1R w KQkq -,48,1678,70535,2476476,102996946,3655148900 -rnbqkbnr/p1pppppp/1p6/8/8/5PP1/PPPPP2P/RNBQKBNR b KQkq -,21,420,9700,214121,5396695,129304435 -2kbR3/8/8/8/2Bp2PP/b2K4/4N1b1/8 b - -,20,519,10177,268014,5651562,150428503 -2k5/6br/2bN4/2B5/8/3K4/8/8 b - -,4,84,2312,44825,1314494,24480603 -rk3b1N/q5p1/1p1p4/1b2p2p/1pnPPpn1/R1B2PPB/3NK3/7R w - -,35,1258,37795,1365208,41481474,1516965672 -bn3k2/8/3n4/B1p5/P1PpP1KN/1p1Pb3/8/8 w - -,16,425,7084,184146,3086552,79820852 -1N1k4/P1P3b1/4p1p1/3P2rp/R4B1P/8/2nKb2R/1r6 b - -,3,101,4447,145113,5725617,188826987 -2k2q2/2Pb1rb1/2r5/1p1pp3/1p1P2B1/8/5BPn/4K3 w - -,17,647,10395,405980,6580211,263736586 -1r1k1b1Q/p3p3/n7/p1pb1n2/1P1Pp3/B2N1N1p/5PPR/R5K1 w - -,40,1505,59867,2135705,84912489,2903914632 -4k3/5r1p/7P/pppR4/1Pn1p1r1/P1b5/2N4K/5B1Q b - -,45,1195,45510,1252930,45723844,1320562816 -6b1/8/p1r1Pn2/P1kP4/7p/K1pB3N/6P1/3N2R1 w - -,29,563,15869,323150,9076595,194111272 -4N3/7k/7p/np1pP2P/P2p1R1B/4R3/b4PP1/3K4 w - -,37,445,14362,179657,5564571,72318926 -1Nb1k3/6b1/P3p1p1/2BPr2p/2P2P1P/8/4R1r1/n1K4R b - -,26,884,24862,771057,22718509,674707786 -7k/8/1p6/1n6/8/3b4/7n/K7 b - -,21,43,942,4096,91613,369602 -8/7P/2B1k1P1/4P3/1K6/8/2bB4/8 b - -,11,325,3354,95780,1024013,28903709 -8/2r2P2/7R/Q7/1p2Bk2/8/1b2K3/8 b - -,25,1253,25808,1193342,23961670,1057918361 -k2B4/n7/7p/3p4/8/1q1p4/4N1Kn/3b4 b - -,27,474,14465,237258,7593958,120801746 -4R3/3K4/8/P7/2b5/8/7k/1q6 b - -,37,628,19423,295296,8949135,132941793 -6nr/P1p1p3/n3br1k/bpP1Ppq1/6QP/N2B1KP1/P3pP2/R5NR w - -,40,1429,49163,1766663,62368666,2267277610 -5knr/2p5/pr4pp/PP1p1p1q/1n1P1P1P/1P1bP3/1B1KR3/RB1N4 b - -,32,659,21664,458391,15496321,341638413 -3r4/n7/3P1kp1/pP3p1r/P1b2P1p/b2pP1Q1/6Pn/3RK1R1 w - -,20,651,13107,445102,9598802,332473249 -n1kq4/4Q3/3p3b/r2P1bpp/p1P1NPP1/pP2P2P/4K3/2R1NBR1 w - -,48,1259,55261,1564035,65933246,1957580926 -5k1b/2b5/1p5N/PP6/4K3/8/4R3/5B2 b - -,18,396,7087,174370,3160874,80586148 -3k1b2/pn1r4/1P2B3/P1pNp1pP/2P5/R4R2/8/4K3 b - -,19,777,13599,519655,9238957,339781192 -1rr3n1/1p5k/1P2p1p1/1Pb2p1p/1n3P1P/8/1R6/3K3b w - -,14,452,5642,193453,2452052,86594727 -rnb1kbnr/p1q1ppp1/2p5/1p1p3P/B7/P3P3/1PPP1P1P/RNBQK1NR w KQkq -,24,906,23310,860387,23378066,853798419 -1rb3r1/p4k2/B2ppn1b/P2PP1p1/6Pp/R1p2N1P/2P5/1N1QBK1R b - -,33,1210,36609,1355848,39821690,1491465053 -4k2b/1B5N/p2p4/P1r1p1P1/1Q5p/N1P4P/4K2R/1R6 w - -,48,703,33127,501021,23227228,358199833 -6Q1/p6k/P7/2P5/8/1P6/5rRK/r7 b - -,1,22,390,10023,181886,5150127 -3R4/6r1/1B6/8/1N2kP2/7p/4K2b/5R2 w - -,42,729,27718,454224,16690662,286315684 -rnbqk2r/1p1pbpp1/p1p1p2n/6Pp/8/P2PB2P/1PP1PP2/RN1QKBNR b KQkq -,30,762,23120,608495,18803006,512283753 -k7/4Br2/pQ2b3/Pp6/1P6/3p4/3K4/R7 w - -,38,653,23152,409423,14216389,256064736 -8/p5k1/P7/1p1p4/3P3p/7P/4N1K1/B2q4 b - -,23,202,4539,40288,873861,8419779 -rk3b1N/q7/1p1p1n2/1b1Pp1pp/1pn1Pp2/2B2PPB/2RNK3/5R2 b - -,40,1158,45552,1358023,53219250,1620473071 -3R2N1/k3n3/3PK3/1p1R4/1pq4P/1P6/8/6r1 w - -,18,614,11820,391759,8204147,264346122 -2N4R/5k2/p1K5/p7/P7/N1p3N1/8/3n4 w - -,32,256,8074,74609,2286784,23575222 -b1k5/8/8/3p4/P2n2pp/2Q5/1K2B3/4r3 b - -,6,182,3862,105085,2311808,62528005 -rn3b1r/1kq1p3/2p2npp/Pp3b2/7Q/2PPP2P/P4P2/RNB1KB2 b Q -,42,1234,49419,1463588,57455473,1712959062 -r4b2/4r3/3k2pp/P2np3/4n1P1/R1PPPB1P/3Nb3/2B1K3 b - -,42,890,34042,751251,28408063,654106063 -4B3/8/7B/2K1PkP1/pp6/P7/1P5p/2R5 w - -,31,306,9116,101743,2913553,37429042 -8/6N1/1p6/8/5k2/8/8/3K4 b - -,8,69,499,5068,35413,383252 -1kn3b1/7P/pr6/P1p3B1/1P6/1P2RB1P/1N2K3/r6r w - -,41,1535,56246,1991065,71947697,2480821126 -rnbk1r2/p2p3p/2pbp3/2P4n/P5q1/1PNp3n/1R1P3R/1QB4K w - -,19,990,17405,837906,16376652,746762088 -1B3N2/1r4kr/nPR2b2/1b2P3/3K2pP/6P1/8/4R3 b - -,31,953,28109,831180,24970497,721274740 -4nkr1/6n1/B7/8/4N3/8/1K6/8 b - -,9,207,3396,71533,1369848,27252392 -4n3/6k1/4P3/8/7p/8/5K2/3B4 b - -,11,165,1797,25314,283746,4075037 -8/P3kB2/n7/7R/3NK3/1p5P/8/2R2n2 b - -,15,600,8038,318416,4394187,171309132 -1N4Q1/8/1N3k2/8/3pbr2/3P3K/4Q3/1R6 b - -,20,948,13187,614723,8930757,409616642 -1n4k1/8/4N2p/Pp1p3P/P2pP2B/4RR2/b4PP1/3K4 w - -,37,458,15252,202543,6604013,92024814 -8/8/P2K4/8/8/8/2b4R/4k3 b - -,11,240,2571,52621,611253,12253959 -2kr3r/5p2/p2p3b/Ppp1QpP1/3R4/n4R1b/1P2K2P/2B5 b - -,28,1310,34728,1441105,38587886,1505629146 -r3kbr1/p1p2ppp/2n4n/1p3bq1/P2pp1PP/1PN2P1R/2PPPK2/R1BQ1BN1 b q -,45,1146,49887,1305153,55459530,1496041822 -8/2r5/8/5k2/3B1P2/3N3p/4K3/3R1Rb1 w - -,32,736,20404,444689,12664718,268881346 -6nr/p2k3r/n5Q1/Pqbp3p/Rp1PP2P/1P3PP1/4N3/1N3K1R b - -,28,954,23549,803926,21684260,739203799 -r3kb1r/1b1pn1pp/2p1p3/p4p2/pP2P1P1/N5P1/2PP4/RNBQ1BKR b kq -,27,909,24374,839565,22677167,803665476 -1n6/BP1n1k2/b7/4PP2/2p4P/4Kpr1/8/7R b - -,23,461,10962,225721,5549667,116980038 -7k/8/4P3/6N1/P3P2p/6b1/N5K1/8 b - -,11,164,1861,27890,329022,5158351 -q7/R7/7B/4P1P1/3K1k2/Pp6/8/8 b - -,20,323,6888,108858,2382133,38703423 -1B6/5r2/1bB1N2k/Pp1R4/4K2p/8/8/8 w - -,37,918,30767,692539,22585759,488101030 -8/p4k2/P7/1p1p4/3P3p/2N2K1P/8/B1q5 b - -,25,259,6554,62512,1454671,14275640 -2bq1b2/4k3/1p3ppr/2pp1Q1N/3p3P/2P5/PpN2PP1/1RB1KBR1 w - -,48,1167,50170,1316696,54670654,1524459278 -rn3b1r/p1p1p2p/B3kp1n/1p4p1/8/N7/PP1P1PPP/R1B2KNR b - -,20,457,9313,222070,4725709,117843662 -8/8/2NkP3/P6R/3n2P1/3b3p/8/K7 w - -,23,508,9964,197730,3875080,73471791 -8/P1k5/4n3/1R5n/1p1N4/7P/2B2K2/2R5 w - -,45,566,25154,334522,14502888,200012053 -7k/1K6/5N2/1P6/6r1/5n2/8/8 w - -,17,387,5160,106972,1242083,25738134 -2k4b/P1P5/2N1p1p1/3P2rp/R1b4P/6B1/6R1/3Kn3 w - -,38,953,33057,826733,28703993,722545560 -1r2kbnr/p1q1p3/n2p1pp1/1p5p/2P1N1bP/3PP1P1/PP3P2/RNB1KB1R w KQ -,26,940,24643,898038,24162298,886790539 -N4b2/2B4r/5P1k/8/PpP3P1/8/2Bq4/nKR5 w - -,29,853,21723,654713,16876957,514703771 -2k2b1r/1q1b1Np1/rp1p4/n3p2p/1pPPPpn1/RN4PB/4KP2/B1R5 w - -,36,1329,45631,1686494,57831117,2164012879 -3Nk3/p5r1/b2p3p/5P1P/PbBp2p1/7R/QrPRn1P1/4K3 b - -,35,1153,37179,1184184,37694021,1187087619 -7R/P7/1P4P1/3b4/3p1k2/3P3K/1r6/3N4 w - -,22,573,11728,268833,5878916,126225775 -2b3r1/1r1p1p2/1N5k/p7/PnP2PPp/1P1P3P/1R1K1B2/Q1N1q1n1 w - -,2,56,1273,34619,880945,24051600 -1n2k3/r1Q1bN2/b2p3p/RPP2P2/1P6/2Rp1Pr1/4qKB1/7q w - -,1,45,1303,48964,1457269,55948795 -4qb2/r4k1b/1pp1pnpr/p2P3p/4NPPP/1Q1P3R/PP2NKB1/R1B5 w - -,46,1496,63664,2085693,89076763,2954646744 -1n1q1br1/1b2pkpp/8/1NppP3/B1NP1pn1/1r4P1/PBP2P2/2RQK1R1 b - -,42,1435,53098,1846973,66453034,2350539992 -6b1/4bk2/1pq1p1pr/p1pn3p/P2P1PPP/1QN3N1/1P4BR/R3BK2 w - -,42,1409,57713,1920502,80085991,2644606424 -Q7/6k1/8/5p2/p2p2b1/6P1/5bP1/2BR1K2 b - -,16,423,6245,181289,2777792,83960599 -4N3/5k2/4R3/1B2BbP1/1P5R/p3p3/8/6K1 b - -,14,665,8273,361669,4557419,188535505 -6k1/1R6/8/2B5/3p3b/5bp1/K5P1/8 w - -,28,423,9805,159503,3557712,60486602 -k7/4r3/8/8/2pK4/2P5/8/6N1 w - -,6,101,878,14118,135831,2182775 -8/8/P1pnk3/6p1/5r2/1P4N1/2NBK2R/b7 w - -,33,1121,34998,1080330,33380097,969934357 -K6k/8/8/1P6/n7/6N1/8/8 b - -,7,62,584,5753,55622,580086 -1r3kb1/Np2q1r1/N2p3n/B6Q/P1P2pPp/3PPP2/1P1K3P/2R2B1R w - -,46,1462,62966,2094535,89594205,3033558785 -2r3nr/nb1p4/4k1pb/pppR2p1/2P4P/P3KP1N/4P2P/5B1R w - -,25,597,13293,345777,7755675,214879442 -8/Q7/5k2/1P1P4/3P3P/8/2n1K3/1N6 w - -,29,226,5711,47193,1219526,10722334 -k7/8/8/8/7b/3n4/2B5/5K2 w - -,8,136,1431,23130,264436,4378039 -2r1nbr1/3kp1Qp/7n/p1p2p2/1p5P/2Pp1R1K/PB1N4/RN3B2 b - -,24,876,21895,756516,19868527,687395927 -2bq1bn1/r1pkp3/n2p3p/3P1pp1/ppP3P1/PPB1P2P/2Q2P2/RN2KBNR w KQ -,36,662,23474,495417,17463335,406740844 -3rkb2/p7/n1Q5/n2b4/pP1p4/1R1N1p2/5P1K/B5n1 b - -,5,151,4194,122345,3544713,104419725 -6r1/3k1n2/4Nn2/8/8/8/1K6/3B4 w - -,23,642,12808,334185,6305566,159915761 -8/2n3k1/8/rb3pP1/1pRp3p/1P4nP/8/1K6 b - -,31,364,11207,145448,4457921,59570408 -B4rnr/2p1p3/n6k/bpP1Pbq1/6pP/N5P1/P1B1pPK1/R5NR w - -,32,1390,43247,1892584,58837205,2577869765 -r1bqk2r/1p1p1pbp/4p3/p1P1nPp1/3p4/5P1N/PP1K2BP/RNBQR3 b kq -,32,887,28297,855714,27394463,879492626 -8/1k6/1P5p/5p2/7r/b2P4/4N1K1/B7 b - -,26,473,11345,199566,4617715,81609942 -7k/3n4/1p3B1P/1P1p3b/4r1R1/3b1BK1/3p4/8 b - -,2,46,1448,33472,1068274,25102763 -7r/R6p/2K4P/5k1P/2p4n/5p2/8/8 w - -,22,360,6343,117402,1991991,39283474 -br1qk1r1/2p1p2p/1p4pb/p2pPB2/P1PnN3/2K1BP2/1P4PP/RN1Q3R b - -,33,1569,48215,2161223,67363691,2891981424 -1n2qbnr/4k1pp/bp2p3/r1p2p2/PQp1N1P1/B4P1P/3PPKB1/R5NR w - -,36,1110,40453,1215286,44208165,1344248458 -7k/8/8/1p6/1n6/8/7n/4K2b b - -,19,73,1498,7119,152000,684677 -8/4k1N1/2R2n1p/3p2pP/pp1P2p1/8/2P1K3/R3Q3 b - -,13,518,5451,212150,2247821,85848358 -8/2N2n2/3k4/PP1p3P/5pb1/1p1P2R1/6K1/7N w - -,18,371,6930,130441,2574607,46703379 -6r1/7b/n4k2/7K/8/3p1B2/8/R2r4 b - -,36,676,22173,418415,13500384,258648398 -r2qk1nr/1bppp2p/1p4pb/p4p2/P1PnP3/1Q1B1P2/1P1B2PP/RN2K1NR b KQkq -,37,1228,44288,1488363,53036938,1811453524 -3k4/8/P7/2p5/P1P2p2/3N4/6K1/5R2 w - -,26,149,3281,21507,480092,2933972 -3rkb2/4pprp/2P1nnp1/p7/pP6/2P4b/3B1P1P/1RNK1BqR w - -,17,648,12781,495084,11015231,429085590 -8/4k3/N7/1p1KP3/2N4P/R1P2p2/r7/8 w - -,20,317,6665,103441,2283872,35714417 -8/5B1n/6n1/P1k2P2/1p6/5R1P/3R4/1K4N1 w - -,41,464,17821,213479,7765558,100614001 -8/6k1/8/2PP4/1K6/6p1/4p2R/4r3 w - -,19,253,4342,73129,1219256,22518357 -6r1/1bk4P/p4R2/Ppp5/1P3n2/1P3B1P/1N3K2/1rBr4 w - -,39,1653,55092,2118506,69278872,2525334525 -1r3B2/4r3/p3N1kp/P2B4/1PpbP3/3p4/3K4/2R5 b - -,37,979,30243,820897,23704030,652030638 -5k2/8/np6/3K2b1/3p4/5p2/8/6n1 w - -,7,157,820,18323,95942,2168936 -1n1b2K1/3n4/1k6/2p1P3/2Pp4/3P4/8/1b6 b - -,19,92,1878,9912,209215,1115219 -8/6k1/br6/5pP1/1p1p1n1p/1P5P/8/K2R1n2 b - -,34,374,12080,149001,4608017,59470717 -1N4Q1/8/1Nb2k2/r7/3p2K1/3P4/Q7/1R6 b - -,26,1264,20583,985148,15471071,735305699 -2b1qbn1/6kr/ppnp3p/5ppP/P2P2P1/1P2rP2/2P1PR1N/2RQKB2 b - -,41,620,24782,439747,17085226,346231300 -rnbqkb1r/3pp2p/1Pp2ppn/p7/6P1/5N2/PPQPPP1P/RNB1KB1R w KQkq -,34,720,25567,613437,22375784,586828492 -6n1/2k1N3/6P1/b7/8/p7/6rN/7K b - -,27,244,6076,65824,1701333,19762239 -rnbqkbr1/pp1ppppp/B1p5/8/3P1Pn1/4P3/PPP3PP/RNBQK1NR w KQq -,33,823,27097,708304,23524221,655206713 -6N1/N7/3p4/8/2b2k2/4R3/8/2Kn4 w - -,24,445,9704,170699,3651893,63141125 -3R4/2k5/8/p1r5/4B2p/R7/3K1P1b/1r4N1 w - -,44,1376,48249,1428552,47844939,1391740177 -3k4/1n6/8/4Q2p/1r5P/5R2/1K6/8 w - -,7,117,4361,60989,2049095,31035441 -1r6/3k3p/2R4P/3p4/p7/1p3Kp1/1b6/8 w - -,19,465,7876,189765,3060154,73696553 -k4N2/r7/2P1K2n/1p1P3p/1p5P/1P4R1/7q/7R b - -,30,750,22912,522883,15700834,353655815 -r1Q5/5P2/8/4bBk1/1p4P1/8/4K3/2R5 b - -,27,1273,30073,1330277,29163213,1246653718 -8/B7/5Q1P/8/k2P4/2R5/8/1Kb5 b - -,10,421,3798,154079,1389120,54943734 -1n4nr/P1p1p1k1/4br2/bpP1Ppq1/6QP/N2B1KP1/P3pP1R/R5N1 b - -,39,1571,61211,2366746,93763186,3563864349 -r1q2bnr/ppp1k2p/2np1p2/4p1N1/P1P3b1/1P4P1/3PPP1P/RNBQKB1R b K -,35,942,32972,927640,32496444,961506642 -r2nk1nr/p3p3/b1qp1p2/1pp3bp/PP3pPP/2PP3B/4PP1R/RNQK4 w kq -,27,914,25380,879811,25368396,893140466 -8/2kN1r2/2nN4/8/3p4/8/K2n4/8 w - -,17,418,6472,158463,2313947,57478383 -8/6b1/1k4P1/1bR5/5N1b/1N6/2K5/8 w - -,27,684,17897,444113,11435671,280656391 -1n4nr/P1p1p3/4brk1/bpP2pq1/3pP1Q1/N2BBKPP/P4P1R/1R4N1 b - -,34,1350,44148,1725479,57637540,2243095097 -k7/8/n5N1/2P5/8/1B6/1K6/8 b - -,7,158,1260,25592,230262,4526868 -2r5/5b2/p3Pn2/P1kP4/7p/2pB3N/K5P1/3N2R1 b - -,27,793,20679,581765,14826035,414104033 -Q7/6k1/8/5p2/3p2b1/p3b1P1/6P1/2BRK3 w - -,25,420,10758,179271,4991788,83306291 -2N1R3/5k2/pK6/p6N/P7/N3n3/8/2r5 w - -,24,502,11788,224581,5589210,106524685 -8/8/8/1k4P1/R1b4P/8/1K6/8 b - -,13,250,3185,58314,757259,13937245 -7k/1pr1n3/rP2p1p1/5p1p/5P1P/6b1/R7/3K3b w - -,15,496,5985,204027,2545578,87584988 -8/2K2k2/p1N5/p7/P7/8/1N6/r7 b - -,17,292,4670,74388,1227212,18733506 -r4b1r/p2bpk2/2qp1ppn/1pPP3p/2P1N2P/N3P1P1/P4P2/R1B1KBR1 w Q -,26,843,23333,771397,22186860,742999366 -6b1/1r1Bk3/1p2P2N/P4P1K/6P1/n5R1/8/4Bb2 w - -,27,567,15522,331186,9274823,204802789 -8/8/1kb4r/8/6p1/6Kp/8/8 b - -,27,106,2924,13010,360044,1586687 -2rb4/r7/6k1/1p6/3p1KP1/R1N2NB1/1p6/8 w - -,30,1027,27793,944594,25173921,860821480 -q7/6r1/5P1k/8/1pP1R1P1/3Kn1b1/8/1B6 w - -,17,779,13079,529160,9498657,355164873 -2b1k3/r2qbpr1/n1p1p2n/1p1p4/Pp5P/2PP1P1B/4P3/RNBQK2R w KQ -,34,1317,42717,1664224,54615698,2147314539 -5r2/1k1n1p2/1p5b/pPp1p3/B5K1/2n4R/PN6/2R5 w - -,31,969,27589,830648,23574362,693776128 -1n3rk1/3b3r/1p5p/p1P5/3b3p/4Pp2/5K2/1N1R2RB b - -,5,123,4003,97145,3199748,80644359 -1k4r1/1b1B3P/p2R4/Ppp5/1P6/1P2n2P/1N3K2/1rBr4 w - -,37,1477,45894,1720668,52789407,1908827211 -5rn1/p1n1k3/q1bp3P/2P1pp2/p1P2pPp/Q2PR3/2KNPP2/R4B2 b - -,43,1427,55608,1830415,69683095,2313545908 -7k/7N/P5P1/3p4/6B1/4p2P/8/2RKN1b1 b - -,6,143,1054,27189,242807,6576824 -2k4r/p4p2/1pp1pn1b/1n5p/2B1b3/2P2rPP/PP4K1/R1B3NR w - -,23,1030,22011,972087,22584461,977969678 -3k3r/7R/8/2Pp1P2/p5n1/3KbN1N/2R4P/4q1r1 b - -,38,1033,39882,1058374,41733886,1095246064 -r1b1kbnr/p3pp2/1pp2P2/1n4pp/4N3/2Pq3P/PP3KPR/R1BQ1BN1 b kq -,47,1479,62916,2071968,84585836,2889948686 -r7/p1p2kp1/n3b2p/Pr2PN2/2P1P3/1P2bPP1/2K1N1q1/1R6 w - -,24,1121,26128,1200208,27816556,1257729195 -r4b2/p1qb2kr/1p2p3/1Pp1p2p/P1K1BP1P/5N2/2PQP2B/RNn5 b - -,30,1079,32590,1145212,35163239,1216830913 -3krb2/1R6/2P1N2n/3p1P2/8/6P1/3N4/2nK4 b - -,2,60,1259,32233,740237,17757928 -8/rk6/5pP1/p1pP4/P1P1P1q1/1P3p2/N7/1RBK3R b - -,24,599,14841,376429,9633183,249432380 -rn6/p2p2qk/1pp1p3/1R3pp1/P4P2/N3Q3/3K1Pb1/2B3N1 b - -,33,1161,36419,1266046,38742454,1338360090 -8/k7/2B1P3/8/6p1/KQb2R2/6P1/8 b - -,14,480,5117,181861,1923943,69493764 -r4r2/4k2p/1p2n3/5pp1/P5P1/4K2P/4b3/1R6 b - -,41,721,28309,476612,17828829,297055350 -1n2k3/r1Q1bp2/b2p3p/1PP1NP2/1P6/R2p1Pr1/3p1KBq/2R5 w - -,44,1513,54396,1894958,63760710,2266484134 -r2qkb1r/1ppbpppp/2n2n2/p2p4/1P4P1/3P3P/PBP1PP1R/RN1QKBN1 w Qkq -,29,893,26174,835411,24901396,819143951 -5kr1/4q1nb/1p2p1p1/p3B2P/4BP1P/3RQ3/1P1N4/1N3K1R w - -,51,1154,59594,1346981,67925843,1603538730 -8/8/1qB1k3/1p6/3p4/1p6/8/4K3 b - -,18,247,5330,67662,1591099,19124885 -4b3/1k6/p7/Pr6/1R6/4B3/3p4/3K4 b - -,12,256,4798,97339,2019623,40826372 -4b3/8/7P/8/3k4/5rb1/4p3/7K b - -,40,114,4442,18544,650665,3629131 -Br3B2/4r3/pb2N1kp/P7/1Pp1P3/3p4/8/2RK4 w - -,23,673,16176,461411,11426583,320621907 -1Nk5/P1P3b1/4p1p1/3P2rp/R4B1P/3b4/2nK1R2/5r2 b - -,39,1116,41810,1231918,43941842,1321585474 -1rbqkbnr/pppp2pp/4p3/5p2/8/4P1Q1/PPPP1PPP/RNB1KBNR w KQk -,36,998,36530,1021334,37515720,1074843564 -4k3/R6p/2b4P/3pr3/p7/1pb2Kp1/8/8 b - -,26,342,8655,111822,2963935,38563809 -b1N1k3/8/2r5/5np1/2p2P2/p1B1p1PB/8/2KR4 b - -,24,814,20328,632226,16645926,498434534 -3k4/5K2/1r6/8/3P2R1/P7/8/6N1 w - -,17,277,4996,78334,1512451,23538898 -8/4k1B1/1p5r/1N2pb2/1P3P1P/p2R4/6B1/1N2Q1KR w - -,54,1202,60825,1276551,62695904,1303417606 -1rb1k2r/1p1p2Q1/p1pb1n2/qB2P2p/5p1P/1PP1PP2/P2K2P1/RN4NR w k -,41,1116,39548,1059681,36656847,988720252 -rnb1kb1r/1p1p1ppp/p1p2n2/4p3/P5P1/1qB1P3/2PPNP1P/RN1QKB1R b KQkq -,38,1008,38047,1102194,41379431,1262436649 -3krb2/2pbp3/6r1/p1q2pp1/p1Pp1P2/2NP1P1P/PBK2RB1/6NR w - -,23,751,17554,563913,13289638,426664152 -6R1/p4k2/nN6/3r4/3p2K1/5p2/3B1b2/6n1 w - -,26,616,14627,358966,8330967,209690954 -rnbqkbr1/pp2ppp1/B7/2pp3p/2PP1Pn1/P3P3/1P2K1PP/RNBQ2NR w q -,30,878,27174,840917,26563615,852322694 -r1b1kb2/q3p1rp/2p3pn/Pp1P2B1/2P1P3/N7/P3NPPP/R3KB1R b KQ -,34,1143,38804,1278011,43977397,1436776988 -4Qr2/p4r2/8/q3pk2/PB3ppp/1PnPP2N/1RK2PP1/1N3B1R b - -,35,1302,39311,1423025,45146902,1639163584 -rnbqkbnr/1p4p1/3pp2p/p1p2p2/7P/2PP1P1N/PP1NP1P1/R1BQKB1R b Qkq -,30,784,23151,638663,19171633,553146401 -4k3/rb1p2br/nPQPp1pn/5p2/pP2PB2/5NP1/P3K3/RN3BR1 b - -,28,1193,33877,1415562,41886707,1733700970 -2rk4/7p/7P/8/2Rp4/8/1p1b2K1/8 w - -,18,383,6127,146504,2257393,58409273 -3k4/p2r4/b2p3p/P4P1P/1bP5/3p2pR/3R2P1/3K4 b - -,20,275,6283,95559,2291876,37612035 -4k3/1r1bp3/3nP1r1/p5pP/1N2Q3/5P2/4K2P/1R5n w - -,41,1133,42945,1203816,44176095,1252368504 -3qkb1r/1ppbppp1/r1n2n2/p6p/1P1p2P1/B2PP2P/P1P2PBR/RN1QK1N1 w Qk -,31,1017,31664,1085160,34194490,1215653389 -5n2/7k/4p1p1/7p/1b5P/3r4/8/5K1B w - -,11,314,3492,94483,1103456,29563670 -rnbqk1n1/1ppp3r/p3p2p/5p2/1b6/2N1PQ1N/PPPP1PPP/1RBK1B1R b q -,32,1120,35218,1271536,40386038,1485597066 -rnb2br1/pp5p/4pk2/4npp1/P1PQ1BPP/2P1N2N/4PP2/1R2KB1R b K -,27,1147,29524,1229299,33246005,1376173407 -rnkq4/p5r1/b1p3pp/1p3p2/1P2P1P1/1PK2pRP/PB1PN3/R4B2 b - -,37,821,27038,639246,20146124,498619859 -8/1k6/6pr/7p/PBR1pP1P/3p4/6KR/8 w - -,28,277,8076,90440,2674041,36458585 -1k6/2N5/2b5/8/8/B3r3/5K2/b7 b - -,36,547,17041,259327,7648855,117471657 -6k1/2b5/8/6b1/8/3K4/8/8 b - -,23,140,3082,19123,415054,2421749 -4k1r1/1b1n4/1B2n3/1p1r2pp/pbpp4/P3PPP1/5N1R/RNK2B2 w - -,33,1339,42693,1672700,53058277,2047708064 -q7/7N/2Np4/8/2b2k2/4R3/8/2Kn4 w - -,29,960,23619,737053,16701768,509620424 -r1b1kb2/p2p3r/n3N2p/1p1ppppP/2q5/P7/1PPBPPP1/RQ2KBNR b Qq -,41,1381,49785,1626177,56933097,1844931356 -k5nr/r2N4/8/np1P2Pp/1p1P3P/1P3N2/3q1K2/6RR w - -,3,74,1415,39745,859305,26249871 -4Q3/q7/6k1/3K4/5B2/8/8/8 b - -,5,155,2599,60803,1109181,25377347 -1k6/6r1/Pp4P1/2R5/2P5/6p1/6B1/3K2N1 w - -,28,335,8823,115471,3041666,41493102 -N7/6nr/1p1B1P1k/8/2Pb2P1/1p1B4/P1Rq4/RK6 w - -,30,926,23165,709254,18497167,584038359 -B2k1B2/3b4/7P/4P1P1/1K6/8/8/8 w - -,20,226,4924,54814,1227534,13815325 -1r1q2nr/p1pbkppp/2npp3/bp4P1/3P1N1P/2N5/PPP1PP1R/R1BQKB2 w Q -,28,734,21354,594631,18314499,533991110 -8/7p/7P/3K2kP/2p1r2n/5p2/1R6/8 w - -,18,351,5364,106594,1643654,33727992 -1rb1kbnr/p1q1pppp/np4B1/2pp4/P1PP4/2N1P3/1P3PPP/R1BQK1NR w Kk -,44,1341,56838,1817791,74742780,2477306109 -1n6/3k4/1p6/6N1/1Kp2P2/1p6/8/8 b - -,12,130,1468,15574,183568,1922645 -1n6/3q1k2/2rP4/3K1P1p/1P6/8/2R5/4b3 w - -,17,533,7454,248550,3403824,116612901 -R7/p7/1kBqP2Q/8/1P3bp1/3R4/2K3P1/8 w - -,49,1328,55805,1551325,63705122,1724915161 -1nb1kr2/r2pbp1p/6N1/QPP2P2/1P1p4/5P2/3pK1Bq/R1R5 w - -,36,1515,48048,1960924,61576208,2454585292 -rn3k1r/1b2p3/1N3ppb/pPpP3p/5P2/P1Q1P3/RP4Pn/2B1K1NR w - -,34,904,30657,854162,29637320,855512474 -1nb4k/4p1r1/5pp1/1Ppp3p/5PPP/BpbqP3/5KBN/1NR4R b - -,42,1131,45554,1226731,47881759,1319876547 -1r6/7n/4kbp1/BP5r/5p1P/p1P5/2N5/2R3K1 w - -,22,779,17314,582348,13340507,435832129 -k5b1/2K5/1R6/8/8/8/3b3P/8 b - -,17,314,4949,85897,1401210,24026851 -3nrbnr/ppp1k2p/3p1p2/4pq2/P1P3b1/BP4PN/3PPP1P/RNQ1KB1R b K -,35,844,29241,767543,27012291,755795428 -r3kbn1/8/B4npq/5p1r/pP2PP1P/2P1B3/R3R3/1N1K4 b - -,30,1051,33069,1129379,37262089,1250251977 -2kr1b1r/1b1pn1pp/2p1p3/P4p2/p2BP1P1/N5P1/2PP4/RN1Q1BKR b - -,20,829,17760,724613,16556191,669262889 -4k3/3bp3/1r1nPr2/p5pP/Pp6/3n1P2/N1Q1K2P/5R1R w - -,33,1107,34835,1144893,36396175,1180243985 -k7/5n1p/P2B4/3p1N2/b7/3p4/1q1n2K1/8 b - -,41,860,32431,640260,23411641,432023642 -b3r3/1k1B4/8/3p1n2/P2P2pp/2Q5/1K6/8 b - -,26,801,14983,447494,8400044,239922156 -2k1b3/2Q5/p7/Pr4B1/8/3p4/8/1RK5 b - -,1,15,325,5397,112210,2025058 -1q3bnr/p2k2p1/nrppb3/P6p/1p2P1QP/1P1P1PPB/R1P2K2/1N4NR b - -,28,802,22772,691400,20512945,651829910 -8/2k5/7R/2PP4/2q1p1r1/K4Ppp/8/6R1 b - -,30,578,16384,315221,9092224,176977341 -2R5/8/5k2/r1n4n/1p1p1p1p/1P5P/3K4/3b4 w - -,13,352,4910,135687,1888856,52002608 -1k6/8/P1r5/1p6/2r5/1p4N1/6Kb/8 b - -,29,335,10310,100487,3172552,30653158 -1n6/1P4k1/bB6/4nP2/2p4P/4Kpr1/8/7R w - -,22,523,10961,266973,5701775,142356610 -qBn4r/1b5k/3b4/pN1P1N2/2P1p2p/3BPP2/P3K1p1/B3RR2 w - -,40,1451,52205,1838515,67515813,2371938405 -1R6/6p1/6qn/8/4b1k1/1K6/8/8 b - -,34,527,18606,282214,10080531,146646441 -4rbnr/ppp1k2p/2np1p2/4pqN1/P1P3b1/BP4P1/3PPP1P/RN1QKB1R w K -,29,1068,30764,1166487,34582097,1327492694 -5k2/2b5/1p3b1N/PP6/8/5K2/6R1/5B2 w - -,28,573,15215,287941,7570354,141814600 -3Kb3/8/8/P1R5/8/8/8/7k w - -,18,151,2599,25948,459331,4905243 -8/2r1b1k1/8/5B2/4b3/2pp2nr/1n6/4K1R1 w - -,13,535,7140,298618,4315069,181735732 -7r/6kp/p4n2/pNpP2P1/P1n1B3/r2R4/5N1P/1qbK3R b - -,45,1092,48111,1235222,54450465,1455047169 -1R1r4/p4k2/nN6/n7/1P1p1K2/B4p2/5b2/6n1 w - -,19,562,9986,278089,5072548,140776173 -B6k/8/4p2n/pp2P2p/7P/Q3P3/8/3bN1K1 b - -,15,450,6582,196308,2932948,86791153 -8/8/1K6/4k3/8/3p1n2/8/8 b - -,16,120,1743,10664,152965,920037 -8/8/4b3/k3p2N/8/b1PB3p/2n5/1K6 b - -,26,412,10548,163093,4116528,65172297 -5R2/3pB1k1/B1n4p/Pp1b3P/P2pPp2/5R2/5PP1/R3KqN1 w - -,2,49,1850,44089,1615744,38895094 -Nb4nr/1p4q1/3B3k/5Ppp/ppP3PN/3B3P/P7/R2K1R2 b - -,26,869,23667,769593,21951704,708953124 -1k6/1b3n2/1p6/5Pp1/5N2/KRpp4/7P/8 b - -,23,451,9675,190127,4047863,80660317 -8/8/5r1b/P2np3/2k3pp/2P1P1N1/K1B1b3/B7 b - -,34,664,19608,348692,10006963,172851987 -1r4rk/1p6/n7/B2pp1p1/P1p3KN/4R1P1/1qP3nP/RN4b1 b - -,41,1146,46801,1268638,52497963,1423340850 -rnb1q2r/3p4/pp3p1k/1Pbp3p/3p2PN/2P3K1/4BB2/1R4R1 b - -,32,1040,32387,1004922,32452411,994249612 -2n2B2/8/6k1/2N5/2K3p1/6PR/2b5/3r4 b - -,29,554,14386,299537,7520457,163141199 -1B1k2n1/6b1/2r3pq/5p1r/pPN1nP1P/2P5/R3R3/3K4 w - -,31,1038,30010,986616,28472117,951724335 -6b1/5kPR/8/1P2B3/8/3B4/5K2/n7 w - -,35,207,6940,74460,2481884,29615743 -r1bqkbnr/p2ppp1p/2n5/1pp3p1/P1P1P3/1P4P1/R2PNP1P/1NBQKB1R b Kkq -,29,800,24224,704753,22261366,682086577 -2r5/1p2pk1p/7n/3p1Pp1/2P3b1/2B1R1P1/5N1P/2K2B1R w - -,38,1041,37530,989238,34829300,909982076 -3krbb1/2p1p3/8/pN3pP1/pqPp3r/3P1P2/PBK2R2/5BNR w - -,30,1048,27355,941483,24895972,852759889 -8/8/3p4/8/3K1k2/5B2/8/6n1 w - -,15,119,1396,13480,172141,1734599 -6N1/8/2Np4/5b2/5k2/8/3K4/3nR3 w - -,25,455,10841,186986,4398379,73946215 -5Rr1/rpp5/1k4P1/1p3p1p/3n1p2/P1K2PPb/8/1N2n1N1 w - -,20,602,10904,333675,6180047,189894563 -3b4/5Bk1/5rp1/p3p2p/P1r1PP1P/1Q6/3p1K1R/1R1N2N1 w - -,41,1170,46497,1296496,52004069,1448624630 -2r5/7k/6r1/1B4np/7p/3pP3/8/bR4K1 b - -,41,742,28362,555002,20507660,409650085 -1R1r4/p4k2/nN6/nP6/3p2K1/B4p2/8/4b1n1 b - -,34,716,22431,476607,14489807,310530192 -rnbqkbnr/pppp1ppp/4p3/8/2P5/1P6/P2PPPPP/RNBQKBNR b KQkq -,30,622,19134,437655,13859313,346816230 -1n1k4/N1bb4/pp1n1r1p/3pp3/3pPp2/PPP2K1P/3BB3/1R2q1NR w - -,26,1022,22379,858141,18912796,714115712 -2b1qb2/2k1p3/nrpp1n2/3P1Qpp/pBP3P1/PP2P2P/3NKP1R/R4BN1 b - -,33,1365,43571,1698889,55573497,2103522739 -B7/6k1/1P4P1/pR6/8/1K6/5r2/8 b - -,21,393,7123,150329,2538453,56343129 -rn2kbnr/p3qbp1/2pp1p1B/P3p2p/Rp2P2P/1PQP2P1/2PN1P2/4KBNR w Kkq -,34,817,28635,735487,26267923,713366586 -7k/7n/R3b2P/3B4/5K2/8/2b5/8 w - -,26,510,12815,243451,5992104,114750944 -k3r3/8/6b1/p7/8/8/8/5K2 w - -,3,75,432,11047,53623,1380080 -b7/b2r4/1k5N/7P/P3p3/2K5/8/8 b - -,24,233,5235,55122,1313025,14303393 -r1b3r1/p2p1pk1/np6/2N1q1p1/2P3Pp/1P1PP2n/P1RK3P/1QN1BR2 w - -,29,1134,31715,1174297,33820491,1238408809 -b4r2/8/3N4/p1q1PB1k/2P2P1p/3K4/P7/7R b - -,35,880,28348,723585,23401963,599695578 -r3k1nr/p3ppb1/1pp2P2/1n5p/6b1/2P2N1P/PP3KPR/R1B2BN1 b kq -,32,1012,32754,1037624,33585205,1079333621 -q1b2bnr/r6k/p1PN4/3Pppp1/2PB3P/N2KPPP1/P3B3/4R1R1 b - -,28,996,28825,1023811,30996403,1101653967 -r1bk1b1r/1p2qp2/1n1p2pp/pPp1p3/3P1nPP/B1N2Q2/P1PNP3/3RKB1R w - -,39,1577,57990,2263188,85225871,3261319551 -b3n1r1/k5p1/4B3/2bp3p/P2P4/5nQ1/KR6/8 w - -,43,1019,41627,1021759,40046624,1027212048 -2n5/4rNk1/8/2K5/4bBp1/6P1/8/7R b - -,29,879,23708,650628,17233483,444558032 -8/8/1qP4k/8/K7/7p/8/4Q3 b - -,24,403,8218,151953,3070462,59975835 -q5n1/p2r4/P1P2P2/Bp1p2pk/3P3p/7P/1R6/1Q1b2KN w - -,36,853,30803,756254,27148881,695333107 -2k5/4b3/2N3P1/3q3n/8/8/7K/8 w - -,11,384,3310,117291,1090545,37446867 -6b1/3n4/p1P1P3/P1k5/7p/K1p4N/4B1P1/3N2R1 b - -,13,341,5242,137526,2237568,60187259 -4k3/7p/2b4P/3p4/p1pb1B2/4r1p1/2B2R1r/3K4 w - -,23,856,20165,714325,16810080,580038080 -7k/3Q1n2/pp2p3/PP2P2p/2p1B2P/4P3/3NK3/4N3 b - -,10,429,3875,154929,1454244,54831366 -3r4/3n1k2/p2p2r1/P1pbp3/R5Pp/4PP1N/B2b1QP1/2KN3R w - -,5,173,5710,186164,6290532,204847070 -r3r3/p2k2B1/P1b5/2PPbq2/BP2n3/6P1/1P5P/1N2KR2 b - -,49,1288,57129,1445924,62701156,1591951393 -3BNR2/7k/7p/1p1pP2P/P2p4/3nR3/b4PP1/4K3 w - -,5,61,2021,22725,707331,8396998 -6r1/1bk4P/p2R2P1/Pppn4/1P3N2/1P3B1P/5K2/1rBr4 w - -,40,1248,44935,1414547,49168538,1564465602 -r7/1k6/1P6/K7/6p1/7n/8/8 w - -,2,45,217,4558,26972,568095 -rnbqkb1r/pppppppp/5n2/5P2/8/8/PPPPP1PP/RNBQKBNR b KQkq -,22,423,10042,220261,5612839,137535509 -5k2/6p1/3Kb3/pp1R1p2/P3PP1p/6qn/3N3P/6q1 b - -,45,767,32356,568295,23523522,416706313 -1n4kr/2B4p/2nb2b1/ppp5/P1PpP3/3P4/5K2/1N1R4 b - c3,28,630,16823,375145,10091232,226936527 -r4bkr/p1n1p1pp/3P1Q2/2p5/5P1P/P2bP3/7R/R1BNKBN1 b - -,31,1376,36592,1590549,41027217,1772768862 -1n2b3/6kp/3b4/2pNn3/P1PpPr2/1pBP3K/8/1R6 b - -,41,1039,38158,934306,32799111,776347257 -r7/3kN3/8/2K1P3/1Np1R2P/5p2/8/8 b - -,21,498,8328,196947,3182957,75772366 -8/k6b/2K1Rn2/8/8/4b3/7P/8 b - -,27,358,8257,130380,2874507,47073554 -6n1/8/B4n2/Pp1p1P1p/1k6/1P2pRbP/2p1R3/2K3N1 w - -,18,390,7663,161101,3464237,72766653 -8/k7/2b4P/P1N5/5b2/r7/4pK2/8 w - -,13,499,5077,182597,1879221,64310978 -6R1/6rk/3Q3b/p3p2p/PR2PP1P/2N2N2/5K2/8 b - -,18,1002,15162,780875,11668510,559764617 -rnbqkb1r/ppp1p1pp/7n/3p1p2/N4PP1/7P/PPPPPK2/R1BQ1BNR w kq -,25,623,15975,422910,11426976,321342833 -1n2kb1r/2qbp1pp/rppp3n/p5NP/P1PP1p2/1P2P3/3NQPP1/R1B1KB1R b KQk -,25,780,20290,654616,17574998,588545249 -4k1n1/8/2N5/1K3P2/pb4p1/P7/1R3r2/5N2 b - -,26,656,15841,382246,9136008,216500763 -R7/7p/5k1P/1K5P/r1p4n/5pB1/8/8 b - -,18,390,6734,147770,2701894,60107615 -2r3nr/4p3/q5Bk/1bp1P3/5PpP/4b1P1/7K/R5NR w - -,26,1038,25041,1003013,24170623,977534499 -1k6/8/2B1p3/K3P2p/4P2P/8/7N/8 w - -,15,52,717,2717,38705,166249 -3r4/p1p3p1/n2bP1kp/P1r2bP1/2R3P1/1P6/4N3/3K3N b - -,33,619,20575,395355,13625393,274868490 -4q1b1/4bk2/1pP1pnpr/p1p4p/P2P1PPP/1QN3NR/1P4B1/R3BK2 b - -,25,1090,29652,1286024,36824901,1603247679 -b1N1k3/8/2r5/4B3/2p2P1n/4p2B/p7/2KR4 b - -,23,701,17114,502263,13121280,375408001 -3N2r1/2kN4/2n5/8/3p4/6b1/8/3K1n2 b - -,30,364,10571,135054,3825477,49441279 -1n6/6kp/2bb4/2pNnr2/P1PpP3/1pBP3K/8/5R2 w - -,31,1112,29982,1048628,26373625,905140167 -8/2k5/4P3/8/8/7Q/4BbP1/3K4 w - -,30,415,12431,151205,4643840,53571027 -rr6/1b1Bb2p/p1p3kB/3Np3/1PPp4/5q2/P3P3/3K1RNR b - -,43,1566,53713,1986274,65287904,2414724836 -3k4/3b4/Q6r/1p1KP3/2p4P/1PP2p2/8/RNN5 w - -,32,624,17050,321941,9017759,170463040 -5n2/5k2/8/8/3P3P/N4K2/8/6Q1 w - -,31,262,7449,69366,1933688,17678159 -5r2/R1p5/Pn2P1p1/2r1B3/6k1/1P1N4/8/b3K2N w - -,28,1092,27654,993462,25312502,867600364 -b1k5/3n3p/8/R1Ppq3/P2r4/N2p3K/3P3n/2B5 w - -,11,408,5124,182829,2616375,93514468 -2bqkbnr/1pp1p1p1/r1n2p1p/p2pP3/5PP1/7P/PPPP4/RNBQKBNR w KQk -,28,745,21442,596776,17712394,513521132 -8/1Pk5/1N6/2P2p1p/8/8/6r1/B6K b - -,20,330,4904,85849,1290606,23609330 -3k2nr/p2B3r/n1p3Q1/PqbP3p/1p1PP2P/1P3PP1/8/RN3KNR w - -,4,111,4107,107406,3907822,106237413 -7k/8/5rpb/p3p2p/PR2PP1P/2N5/3QK1R1/6N1 w - -,44,792,33717,584194,24230412,423171970 -5k2/7Q/8/2n4p/7P/4r1R1/8/2K5 w - -,32,512,14021,221460,6348161,102185434 -rnbqkbnr/ppppp1pp/5p2/8/6P1/2N5/PPPPPP1P/R1BQKBNR b KQkq -,19,438,9280,231308,5338058,141890546 -Nb6/4B1nr/1p5k/5P1P/1pPq2pN/p6P/P2R4/R2K1B2 b - -,35,951,30486,867262,27532651,807410684 -r4br1/8/2Q2npp/Pkn1p3/8/2PPP1qP/4bP2/RNB1KB2 b Q -,1,18,888,16244,779306,14947584 -8/k7/3b4/8/6Q1/3K4/6PQ/5B2 w - -,43,575,23498,251338,10438323,106076012 -2N4k/4q2r/N2p4/1p3n2/P1P3Pp/1P1P1P2/3BQ2P/2K1RB1R w - -,41,1207,49414,1476237,60412508,1790273558 -1B4nb/2r1k3/3R2p1/N4p1r/pP5P/2P5/4K3/2R4n b - -,28,957,26119,849952,24011371,770027526 -5B2/7p/4k2P/8/5Pp1/B1Rp3r/N5K1/3R4 b - -,15,473,6250,198007,2671233,85859541 -8/3k4/8/2PPR3/1K2p3/5rp1/6p1/8 w - -,13,228,3362,60162,941052,17629260 -1B6/5R1n/2r1kbp1/5p1r/pP5P/2P5/2N5/2R3K1 w - -,33,788,24484,608485,18929152,483911449 -4n3/5k2/p2p4/P2P4/P1p4Q/b2BK1B1/5N1R/8 w - -,40,423,14854,170671,6092745,73171550 -4q1nr/pp2k2p/1N3p1b/2ppp1p1/1P4P1/B1P1PP1P/P1bP1KB1/R3Q1NR w - -,30,988,29782,941007,28696889,883185365 -rnb1kr2/p2p1p2/1p6/2b3pp/2P2qP1/1PNPP2n/P1RKN2P/1Q2B1R1 w - -,30,1162,34027,1293798,38661154,1464877577 -8/6P1/p2b3p/P3k2P/5R2/1b1p2P1/8/R3K3 w - -,28,516,12966,235832,5985316,107843162 -r3kbn1/pB2r3/1P3p1p/2p1p2P/P1P5/2R2N2/8/2B1K1NR w - -,36,661,23941,487689,17798415,377226654 -4n3/4p1n1/8/p2k3p/Prp4r/R3pK2/1b1NB3/1NB5 b - -,35,616,18731,359301,11084192,226462101 -6k1/6N1/3R1n1p/3p2pP/pp1P4/2Q2Kp1/2P5/R7 b - -,16,575,7927,282827,3622003,127777228 -5k2/4R1q1/8/5r2/P3p3/1p1P4/6NK/1r6 b - -,43,627,22862,343776,12401221,192352873 -4n3/7k/4P3/7B/7p/8/8/4K3 w - -,13,112,1514,14328,201473,2053881 -1r3kr1/p1p3pp/n2Nbb2/P3P3/4P3/2P3P1/1P3Pq1/3RK1N1 w - -,26,1153,26746,1148563,25894699,1091286405 -8/P7/4R3/2p3N1/2P5/5pK1/8/2k5 b - -,6,181,1246,36268,267756,7502361 -3k1q2/r5b1/2P4r/1pNppb2/Bp1P2n1/8/6PR/5KB1 b - -,51,944,41179,884926,38583900,891896903 -1rbq1bn1/ppppp1p1/8/PB3k2/P5rp/B1P4P/3PQPPN/RN2K1R1 b Q -,28,1054,23325,870787,19946435,741484122 -8/8/1K6/8/8/k2p4/8/6n1 b - -,9,67,726,4544,54307,337734 -r5nr/nb1p1p2/4N2b/pppqk1p1/2P4P/P3KP2/3RP2P/1Q3BNR w - -,41,1286,39294,1242371,36492444,1174061173 -r1bqkb1r/ppp1p2p/2n5/3p1PB1/2P4P/3P1K2/PP1N1nP1/R2Q1BN1 w kq -,36,1142,38880,1280062,43385701,1480509115 -b1k5/3n3p/2Pq4/R2p4/P1Nr4/3p3K/3P3n/2B5 b - -,37,566,17256,280044,9065122,153568900 -4Bbnr/p1pr1p1p/1pn3bq/4k3/3pPpp1/2QP1PPP/P1P5/RNB2KR1 b - -,37,1157,36127,1149342,35784041,1163583044 -5k2/2R3q1/8/3r4/P3pN2/1p1P4/7K/1r6 w - -,24,889,15980,580215,10173527,368429210 -r6r/1bpk1npp/6P1/pP1N1p2/1b1p2nP/BP1P1pqR/2P1P1B1/Q3RKN1 b - -,61,1963,106893,3419587,176942430,5703606317 -qBn4r/1b5k/p2b4/3PpN2/2P4p/N3PPp1/P1B1K3/B3R1R1 w - -,37,735,27863,629215,24138668,599226212 -2n5/8/4N1kB/1K6/6p1/rb4PR/8/8 w - -,22,461,8706,210860,4357805,107387992 -qBn2b1r/1b5k/p7/3PpNp1/2P4P/N2KPPp1/P1B5/B3R1R1 b - -,23,848,20945,780083,20541267,771210588 -8/6b1/7r/Pk2p3/1n5p/K1PbP1N1/1B6/8 b - -,35,434,13169,153820,4443875,53243547 -k5B1/8/4n3/2P1N3/1p6/8/8/1K6 w - -,17,192,3499,34669,618670,6187787 -2rk2n1/7q/5np1/1B3p1r/p1p1PP1P/b1P1B3/1P2b2R/RN2K3 w Q -,31,1147,34668,1318644,39544580,1536915124 -r4qnr/p1p1kpp1/1bn4p/Qp1p2P1/2PP3P/1B2P2b/PP3P1R/R1BNK3 b Q -,40,1166,43560,1284082,47807160,1446984917 -8/k7/2B1p3/1K2P2p/4P2P/8/8/5N2 b - -,1,16,50,782,2796,43636 -rnbqkb1r/1pp1pppp/8/p2p4/3Pn3/P4Q2/1PPN1PPP/R1B1KBNR b KQkq -,35,1358,45143,1722128,57789886,2185421041 -rn2k1nr/p1pp1pp1/bp5p/6q1/1b1p1PP1/2N1B3/PPP1P2P/2RQKBNR b Kkq -,46,972,41856,1008569,41486250,1107737308 -8/k2n4/4R3/6p1/1K6/2p5/7P/3b4 w - -,21,365,7020,122080,2209291,38999985 -1R6/6p1/8/6k1/2K3n1/8/3q4/3b4 b - -,39,466,16991,200412,7092421,88232092 -r4bnr/ppp2p1p/2n1k3/1B1qpb2/1P1pP1p1/3P1P1N/P1PNQ1PP/R1B2KR1 b - -,42,1222,44014,1355850,48580001,1558453712 -1r4k1/p7/PRP5/2Pr4/8/4K1P1/1PB5/8 b - -,24,498,10979,227079,4999107,104729711 -2b1kr2/rp1p1p1p/2n3N1/Q1P1qPb1/P2p4/4pP2/1P1NK1BP/R1R5 b - -,42,1737,66944,2641284,98903304,3761209870 -8/8/8/2BN4/5Pkp/1R4p1/5RK1/4r3 b - -,18,608,9029,288387,4236547,133632670 -rnbq3r/1ppp1k2/1b2p1pn/pP3p1p/3PP3/5PK1/P1P1Q1PP/RNB2BNR b - -,36,1012,35127,999959,34334271,1000453608 -4b3/2b5/7P/8/3k1r2/8/4p1K1/8 w - -,6,210,948,33632,182087,6424108 -8/5k2/8/4P2P/8/8/8/N4K2 b - -,6,53,286,3105,16640,192913 -5r1B/pRp3p1/2r1P1k1/P5P1/n7/1P1N4/1b1K4/7N b - -,38,845,28482,627496,20695467,463686132 -1r3b1r/3kp1pp/2p2p2/p1p2n1n/2PPPP1q/8/2RK1N1P/1NB2B1R w - -,26,997,25195,931638,23934247,875813310 -8/1pr2k1p/7n/6p1/2ppB3/2Rb2PN/1K5P/6R1 w - -,32,707,21824,521784,16091931,398979060 -8/7n/B6n/Pp1p1P1p/1k6/1P5P/2p4b/2K1RRN1 w - -,21,411,9581,197274,4913388,103910912 -6n1/3r4/5p1p/2k3rP/P7/2BP1P2/2N2bBK/6R1 w - -,30,898,22995,654491,16620741,463248149 -k7/2r4r/p5P1/PpQ2p2/1P1p4/7b/R2K3B/8 w - -,35,769,25573,545480,17769520,388204490 -2b1k3/4p2p/1r1nP1r1/p5p1/Pp4P1/1Q1n1P2/N6P/4KR1R w - -,4,118,3088,91337,2524735,74953228 -8/8/8/4n1N1/k6b/2R5/K7/8 b - -,15,328,4778,100493,1539496,32114670 -7Q/3b4/1N1k4/1P1p1pp1/P1n2P1P/1p1P1R1B/8/5K1N w - -,41,696,25204,392314,14134662,211439338 -8/r2rN3/2p1k2p/P2p2nP/3Pp3/1P2Kb1R/1BB2R2/8 w - -,29,701,21042,510048,15518487,386952852 -8/8/8/2BN4/5Pkp/R1r3p1/5RK1/8 w - -,35,433,13985,191473,5987920,86580796 -1nbq1k1b/3ppp1r/6p1/1pp4p/Pp2BP2/B3P1PP/3P4/RN1K2NR w - -,29,917,26541,848306,24866014,805606676 -7r/8/2K3k1/8/3b3p/p7/8/4R3 w - -,20,573,10209,272790,4591343,117439265 -8/8/2P2P2/8/1K4kp/p7/7q/8 w - -,10,248,1797,44007,347307,8687169 -1r1k1bnr/pp1bqpp1/B6p/2ppp2Q/P3P1P1/2PP3P/1P1KN3/RNB4R w - -,34,1053,36350,1119516,39844655,1245002265 -7Q/3b4/1N3kp1/1P1pnp2/Pp3P1P/3P4/4R1B1/4K2N b - -,3,123,1334,51501,628120,24162847 -3knb2/p4r2/PP2B3/2p3pP/1NP1p3/6R1/8/4KR2 w - -,37,834,29148,606653,20804071,428088973 -8/8/np1kN3/8/5P2/2K5/8/8 b - -,10,140,1485,18636,196273,2374843 -7k/3b4/1p3n1P/1P1p2Kb/8/5B2/4R3/8 w - -,24,477,10309,198690,4206496,80424882 -3r4/3npk2/p2p2r1/P1p5/Rb2b1Pp/4P2N/5PP1/1BKN2QR w - -,21,831,19902,762827,20462767,757897643 -rn1qk1nr/p3pp2/b1pp4/1p4p1/3bP3/NPQP4/P1P1NPP1/R3KB1R w KQq -,36,1197,40925,1375354,47437234,1606822869 -2b5/6k1/1r6/5pP1/1p1p1n1p/1P5P/1K6/1R3n2 w - -,10,325,3907,117107,1527706,44025612 -8/p7/P7/3P1k2/N4q1p/1K6/1B6/8 b - -,25,334,8312,118995,2880075,43127170 -1n6/3bK3/8/1kp5/8/8/8/B5q1 w - -,12,417,4582,161292,1794282,62926498 -6nr/3k4/3N4/QbP1p3/2PPqp1p/R4PP1/1K2R3/8 b - -,31,1270,36593,1484959,43636980,1741426036 -1k6/8/1p3p1b/pPn1p1r1/B7/2RN3K/P7/2R5 w - -,26,665,17457,425618,11588278,289625749 -rnbq3r/p2p3k/1p3p2/1Pbpp2p/3P1NP1/P1P2K2/3BB3/2R4R b - -,29,1054,29200,1022664,28867905,994729959 -rnbqkbnr/ppppppp1/7p/6P1/8/8/PPPPPP1P/RNBQKBNR b KQkq -,19,417,9025,213463,5158846,131836359 -2bq1b2/5kp1/1p1p1p1r/2p4p/3pQ2P/N1P3N1/Pp3PP1/1RB1KBR1 w - -,47,1152,46503,1229633,48248670,1334140479 -1nbqkbnr/2pppppp/rp6/p7/3P4/8/PPPNPPPP/1RBQKBNR w Kk -,22,439,10786,245032,6649709,166996501 -8/5k2/8/8/1p1p4/1p6/6B1/6K1 w - -,13,123,1650,14461,197310,1795332 -r1n1k1r1/5p2/2p2P2/pP2b1p1/3p3R/P3p3/NBP1P3/2R1KB2 b - -,27,690,18192,458078,12016606,304284207 -8/8/6QP/1kB5/3P4/2R5/5b2/1K6 b - -,8,353,2937,125825,1121630,47251041 -4k3/8/8/4P3/1NK4P/2p2p2/5r2/R7 w - -,29,381,9751,146620,3449489,53916494 -3Kb3/2R5/P7/8/8/8/6k1/8 w - -,18,227,3861,45432,790114,9571457 -8/8/4k3/rR5n/1p3p1p/1n1p3P/8/2Kb4 w - -,3,77,846,21685,264369,6941314 -r4kr1/1bpqp2p/1p2Bbp1/p3P3/P1P1NB2/1P3P1P/2K3P1/RN2Q2R b - -,39,1822,64991,2946452,100680530,4465914433 -4B3/6k1/8/P3P3/8/3N1N2/6K1/8 b - -,5,150,526,14873,64318,1755763 -4rb2/2p1p1r1/2k1b3/p1q2pp1/p1Pp1P2/3P1P1P/PB2K1B1/1N3RNR b - -,30,592,18260,366507,11610954,239210353 -7b/8/1p3k2/PPb2N2/1R2K3/3B4/8/8 b - -,14,335,5102,120409,1959221,47286826 -5r1k/8/3rB3/1p6/3NQ3/Ppb5/6K1/8 b - -,31,1183,33807,1266527,36116814,1298711110 -3k4/4R3/8/3B4/p6p/3K2b1/2r2P2/6r1 w - -,34,974,25535,749540,17967229,533458582 -rnbk3r/p2pb2p/2p1p1q1/1p5n/P7/NPPp2Nn/R2P2KR/1QB5 w - -,21,915,19729,838025,19654596,820990360 -2kq4/4Q3/1n1pN2b/1r1P1bp1/pPP2PPp/p3P2P/4K3/2R1NBR1 w - -,42,1035,39949,1063673,40527181,1137687204 -r4nk1/6bp/p1p1R3/7P/5pP1/6B1/K7/8 w - -,22,477,10321,232266,4991180,116047172 -4r2r/pppkbn1p/5p1n/4p3/P1Qp1Pq1/BP4Pb/4P2P/RN2KB1R w K -,35,1306,43272,1635019,54539523,2079934703 -1R6/8/1kB1P2Q/p7/1P4p1/K5b1/3q2P1/8 b - -,5,177,5178,142526,3817915,109339237 -8/8/8/1k6/3R2PP/3b4/1K6/8 w - -,18,230,4259,53654,1006739,12555575 -1r2kb1r/p3pbpp/n4p2/1pppNn2/4P2P/2PP4/PB4P1/RN1QKB1R w KQk -,36,1035,36655,1056837,37048033,1078738831 -3b4/8/3k4/8/B1P1pN2/2K5/8/8 b - -,12,223,2387,43315,514348,9050627 -1r1k1bn1/pb2p2Q/np6/P1pP4/1P1Pp2p/B4N2/5PP1/R1N2K1R b - -,26,1012,25732,1003569,25773117,1015152815 -b3nbr1/5Bp1/qk2p3/3p3p/P2P4/2K2n2/6Q1/6R1 w - -,32,1099,32646,1136179,33283355,1170302180 -4n1kr/7b/1pq1p1p1/p3B2P/1Q2BP1P/R2p4/1P1N4/1N3K1R b - -,25,1162,27432,1256553,29686673,1350973142 -8/k2n4/8/2R5/1K6/8/2p1b2P/8 w - -,20,424,7914,166766,2917452,62954690 -7k/8/1p6/1n6/8/8/7n/2K2b2 w - -,5,80,417,8120,37872,786394 -5b2/k3qb1N/3Q4/2p3p1/2Bp3P/P1P3P1/2NK1P2/2r4R w - -,51,1566,64268,2112861,85493292,2882252590 -8/6r1/p3kP1p/P2p3P/1b4R1/1b1p2P1/3R4/5K2 b - -,31,719,19232,431368,10992972,245260893 -6Q1/6k1/8/8/3p1pb1/p3b1P1/6P1/2BRK3 b - -,3,63,996,24005,388621,10169898 -N1r2N1k/8/4n3/1B6/P2P4/KPp2PQp/7P/7R w - -,43,678,27988,418289,16607341,262561083 -5k2/3P1r2/p4b2/p1p5/P7/N6P/5R2/1n3K1N w - -,25,497,9730,190530,4064182,86617684 -N5nr/pp2kq1p/5p1b/2pppbp1/1P4P1/B1P1PP1P/P2P1KB1/R3Q1NR b - -,31,824,24358,678405,19632139,568906406 -3k2n1/8/8/8/8/1N6/6N1/4K3 b - -,8,112,1096,16559,168614,2658867 -8/k3b3/8/8/2B5/1K4p1/8/5r2 b - -,28,371,9717,132060,3384992,43257979 -rn3b1r/p1p1p2p/B1k4n/5pp1/8/1p3N2/PPNPKPPP/R1B4R w - -,35,551,18329,342242,11067839,232045693 -2r5/pbkn2r1/2p3P1/1p1B3P/PP1N3R/1PB4P/4K3/1r6 w - -,30,1050,29499,1039118,29925476,1057986610 -8/3n1k2/8/7P/3P4/N3K3/8/6Q1 b - -,11,316,3024,85394,837223,23512301 -rn4r1/p2kpn1p/B1p2b2/2r1Bp2/P2P3P/5N2/1P2KPP1/R6R b - -,38,1667,57981,2352659,79127423,3044355081 -1nb3nr/2p1pk2/r7/ppP2pq1/1P1pP1Q1/N4KPP/P2b1P2/1RB2BNR b - -,51,1276,55688,1531221,63713833,1885217088 -8/8/8/1R6/1k5n/8/Kb6/8 b - -,4,47,575,7985,113056,1672817 -rn1qkb1r/3b3p/pp2pp2/1Npp1np1/2B2P2/1PPPP1PP/P4Q2/R1B2KNR b kq -,32,969,29728,937174,29746762,966669026 -1k6/8/1P6/2P2p1p/8/8/1N3r2/B5K1 b - -,14,100,1414,15676,224513,3157338 -8/8/4P1k1/4K1B1/8/8/8/5q2 w - -,14,340,3519,83383,867305,20326065 -8/k5b1/7N/2b5/8/1K3N2/8/4R3 w - -,29,638,17996,373685,10167277,204878122 -6N1/2p5/1pn5/1p3p2/3k1P1K/8/8/8 w - -,7,102,887,12510,114325,1552003 -3N4/1r5k/2BB4/Pp1R3p/8/8/2K5/2b5 b - -,22,766,15809,555339,11172162,392624491 -r6r/1b1Bb2p/p1p3kB/3Np3/1PPp4/5q2/P2KP3/R5NR w - -,41,1778,63276,2472455,87601204,3231692370 -r5k1/p2n2bp/2p5/5p2/6PP/1R4B1/K7/8 w - -,25,710,18003,498269,12262498,336588722 -2b5/8/2kb4/2P3P1/5N2/1p6/4K3/N3R1b1 w - -,21,528,11154,269830,5942855,144812344 -rnbk1r2/3p3p/2pbp3/p1P4n/PP4q1/2Np3n/QR1P3R/2B4K b - -,53,1046,51941,1103806,51977387,1189743213 -8/3b2r1/rpk5/p3bpR1/PpPpPN2/R2B3P/2QPK3/1Nq5 w - -,29,977,25721,906323,24719727,886722717 -3qkbnr/r1p5/p1np1p1p/1p2p3/1P5p/P4PP1/2bPK1BR/RNB2QN1 b k -,35,694,23931,550391,18914692,483177402 -8/1Pk5/8/2P2p1p/N2B4/8/5r2/7K w - -,18,250,4223,60343,1057869,15597331 -8/3k1R1p/2b4P/3p4/p6r/1pb2Kp1/8/8 b - -,5,75,2189,31087,886237,12202753 -8/rppP2r1/pkn3P1/1P3p1p/1K3p2/P4PPb/8/1N2n1N1 w - -,5,127,1892,50333,853400,22801682 -1r1k1bnN/q7/1B1p4/3Pp1p1/2b2pBp/5PP1/2R2nR1/4K3 b - -,5,137,5464,147271,5854880,163795223 -3k4/8/5P2/8/5K1r/8/4N3/4B3 w - -,7,112,1872,28683,495012,7652986 -8/p6k/P7/1p1p4/3P2Qp/7P/3qN3/B2R2K1 b - -,19,468,6932,189715,2960841,84295681 -4k3/5r1p/7P/pppR3r/1Pn1p3/P1b4K/2N5/5B1Q w - -,4,173,4777,175507,5062105,175178946 -8/2R4p/7P/3K1nkP/5r2/2p2p2/8/8 b - -,22,318,7053,96378,2138075,30765128 -1r1k2nN/6b1/3p4/2qPpB2/R4p1p/3n1PR1/4K3/8 w - -,34,1477,41230,1673161,44347584,1730791953 -8/1r5k/2N1p3/p4p2/P4Pp1/7b/2N2K2/8 w - -,19,407,6468,130507,1960266,39216246 -R7/8/8/2p5/2P4K/5N2/6R1/2k2q2 b - -,12,311,5265,129056,2440026,58794836 -1k6/8/5pP1/p1p5/P1P5/1P3K2/Nr6/R1R5 w - -,18,270,5157,82673,1733716,28194011 -7N/3k4/n7/2P4B/8/8/1K6/8 b - -,10,175,1637,27029,260689,4296707 -3Nk3/p4r2/b2p3p/5P1P/PbBp4/6pR/1QPR2P1/4K3 b - -,24,747,16785,525862,11687462,373309317 -rnk5/5N1b/1p6/3Q4/3PPPPp/PP2B3/b6K/3Bb2R w - -,39,702,26030,515573,19078385,410415494 -1r6/k5N1/3r4/1P6/6p1/8/8/1K4n1 w - -,10,279,2755,75567,775187,21415063 -2r5/2Q1n1k1/1p2p3/p2N1p2/Pp3Pp1/7b/5K2/6N1 w - -,29,667,17643,410720,10855753,249273058 -2N4R/6k1/p7/pN6/P1pK4/2n3N1/8/8 w - -,31,349,9378,97722,2724136,27807718 -5r2/5k2/1b4p1/p1Q1p2p/P3PPBP/8/2rp1K1R/1R1N2N1 b - -,24,827,20199,740594,18334273,702941114 -4rr2/Qppk1n1p/3b1p1n/2B5/P2ppPq1/1P4P1/R3P2P/1N2Kb1R b K -,46,1372,60282,1826006,76739659,2367902601 -7k/rpr5/1P2p1p1/R2n1p1p/5b1P/5b2/8/4K3 b - -,41,495,20591,257050,10288113,134134258 -2b2r1k/1r1p4/N1P5/p4p2/P4PPp/1P1n3P/N2K4/1RQ3n1 w - -,29,797,23174,651241,19547973,557939876 -2b3n1/r1Np4/2nk1ppr/pPb3p1/3p1P2/5Q1P/P2BP3/2R1KBNR w K -,42,1051,42908,1091601,43490988,1126739911 -rnbqkbnr/pp6/3pp2p/5ppP/P1N5/1P5N/2PPPPP1/1RBQKB1R b Kkq -,26,697,18510,503452,14092863,397331299 -8/k7/2K5/8/4pb2/1BN3p1/2r5/8 b - -,23,341,7453,127995,2842383,48623195 -2N3k1/2r5/p4b2/p1p5/P7/N3KR2/8/1n5N b - -,29,591,13912,311019,7278578,168960897 -8/4R3/R7/2p5/2P1K3/q1k5/8/8 w - -,28,420,11221,205535,4924564,95647954 -8/8/P2Rn3/k7/1p6/5N1P/2B3Kn/6R1 w - -,39,486,17820,218428,7975551,101628730 -4k3/3N4/4n3/1B6/P1r5/1P3P1p/K1p3RP/8 w - -,27,539,13585,264719,6614585,137032182 -5k1b/1n6/P1p5/6p1/1P6/6N1/2NB1r2/3K4 w - -,22,603,12498,336313,7036144,186772470 -8/r6k/2n1p3/p4p2/PN3Pp1/7b/2N2K2/8 b - -,24,346,8253,118310,2795113,39694083 -3r1nk1/7p/2p4b/p5PP/5p2/K2RB3/8/8 b - -,21,454,9243,211034,4436743,99717943 -1nb1kr2/r1Q1bp2/3p2Np/1PP2P2/RP6/3p1P2/3pK1Bq/2R5 w - -,6,240,8659,304560,10551308,374047405 -1n6/p1B4k/P2q1P2/Bp1p2p1/3P3p/7P/5NR1/4Q1K1 b - -,26,931,20477,761468,16486255,616272641 -n7/R7/P1p1P1p1/5k2/1r6/1PB1K3/5N2/b1N5 b - -,20,601,11937,337483,6921478,191521996 -8/4r3/4N3/p1b2P2/P7/8/8/1K4k1 w - -,14,334,3919,94214,1062358,25379754 -8/2R5/8/6kp/7p/4P2n/7K/1B6 w - -,25,141,3335,24735,563207,4660127 -rnbqkbnr/1p1ppppp/8/p1p5/P7/3P2P1/1PP1PP1P/RNBQKBNR w KQkq -,28,588,16995,407039,12133213,319658321 -4n3/R7/P1p1P3/5kp1/2r5/1PBN4/3K4/b6N w - -,36,742,22598,474259,13599865,294220986 -r5R1/3k4/8/8/p3KP1p/6b1/B7/6r1 w - -,26,628,14664,382879,8594211,233052722 -6n1/4k3/1b4P1/2P5/7N/p4r2/r7/5K2 w - -,3,89,648,16923,133477,3521396 -N7/2B3nr/5P1k/8/1pP3P1/3Bb3/Pp1q4/RKR5 b - -,33,756,24929,588662,20502885,499001086 -r1b2b1r/pp2p1kp/2n3pn/2pN1p2/P4B1P/2PP4/4PPP1/R2QKBNR w KQ -,40,896,35443,826627,32339687,784206145 -2bq1b1r/6p1/Qp1pkp2/2p4p/3p2nP/NpP1P3/P3NPP1/1RB1KB1R w - -,35,1009,35795,1031772,36776700,1077726092 -4k3/4rB2/p2P1b2/p1p5/P7/N6P/5R2/1n3K1N b - -,5,132,3150,78336,1879094,47636634 -6kr/3n3p/3b2b1/B1p1n3/PpPpP3/3P2K1/8/1NR5 w - -,20,502,8858,235283,4335520,120025756 -6nr/2p3r1/P2k2Pp/P2p4/3Pp1bP/1P1nKR2/BB6/2R5 b - -,30,898,24593,682567,18765955,507617582 -1r2n3/4p1b1/8/p2kQn1p/P1p1N2r/3pp3/1B2B1K1/RN6 b - -,2,70,2303,76133,2508365,83149849 -1k2N3/8/1q5n/1QPP2r1/1KP1p2R/5Ppp/8/2R5 b - -,22,619,13644,405817,9378506,292291361 -rnbq1bnr/pp2p1kp/6p1/2pp1p2/PP5P/2NP4/2P1PPP1/R1BQKBNR w KQ -,32,870,28104,798633,26109337,769294136 -1n1qBbr1/Nb2p1pp/4k3/2ppP3/P1NP1pn1/1r4P1/1BP2P2/2RQK1R1 b - -,40,1403,50058,1782699,61905801,2237748969 -5N2/2k5/8/1P6/7P/pK6/4Rn2/8 b - -,13,330,3589,84345,907130,20459669 -2b1k3/r1np4/1P1P3n/4N1p1/pP3p2/P2KB1P1/3N2Br/b6R b - -,30,1263,39247,1533662,48740318,1807314403 -8/5bP1/p2b3p/P3k2P/5RP1/8/5K2/R2q4 w - -,23,729,14955,464632,10332987,313985062 -8/7k/5b2/1R2B3/3p2P1/5r2/3N1K2/3r4 w - -,4,107,2670,67966,1751559,44631161 -4kr2/1B5N/p2pp2b/P3r3/6Pp/NR5P/2P2B2/3Q1K1R b - -,30,1211,33507,1412622,37951712,1636322628 -rn1kr3/1b5p/2p3q1/p1bpQ3/PP4n1/2Np3n/1R1P2KR/2B5 b - -,49,1665,67916,2181893,91908969,2862513028 -r6r/pp3k2/3B1n2/q3p2p/Pb3pp1/1P1P3N/1R1QPPP1/1N2KB1R b K -,46,1093,46923,1207848,51220974,1422543041 -8/p6k/P1P5/2P2r2/1R5K/6r1/1P2B3/8 b - -,31,606,15673,297475,7293128,141402094 -rn3b1r/1kq1p3/2pQ1npp/Pp6/4b3/2PPP2P/P4P2/RNB1KB2 w Q -,35,1196,38978,1342725,42582894,1489481053 -q2k4/4r3/p3pnp1/7p/P1pPPB1P/4rP1B/R4K2/2B1R3 w - -,38,1342,45260,1574209,52681268,1827984750 -8/8/6kp/1n1P4/6p1/Q2K3n/2P5/1R6 b - -,19,601,10003,308786,4864277,149805336 -4kr1r/2pR3p/1p3p1n/Q4n2/PP1B1bP1/2p4q/4P2P/4KR2 w - -,37,1198,38161,1224946,38510745,1240878143 -2r5/1k2bR2/1p6/1P3p2/p3p3/6K1/PNR5/1n1B4 w - -,31,653,18305,395393,11312076,250922556 -6b1/3kB3/7R/N7/p2p1p2/P2P1K2/4r1N1/1r6 b - -,37,1071,34991,940462,28648278,753485006 -2q1kbnr/rp3p1p/3pp3/3n1PpB/PPp5/3P4/1BQ1P2P/RN2K1NR b Kk -,36,1375,47915,1821754,63455706,2419426655 -5r2/1k4p1/4P3/r2P3P/1P4p1/7N/nK6/8 w - -,13,452,5805,183104,2418232,71819464 -rnb1k1nr/2ppbpp1/1p5p/p5q1/NP1p1PP1/3QB3/P1P1P2P/2R1KBNR b Kkq -,38,1405,53601,1930284,73271710,2640325526 -k7/8/5P1N/5N1P/2p1b1K1/2P1p3/5PR1/2r5 b - -,23,447,10324,211604,4820730,102608928 -1nb1kr2/r3bp1p/3p2N1/QPP2P2/RP1p4/5P2/3pK1Bq/2R5 b - -,47,1372,59381,1679147,69795087,1974475263 -1q2kbnr/1rp4b/p2p3p/nN2pp2/1P5p/P4PP1/3P1KB1/R1B2QNR w k -,29,758,22435,637884,20038269,603838549 -r1r5/1kp1qp2/6p1/p2PpP1p/P1P1P1PP/7B/1PQ1KR2/RNB5 b - -,31,1135,33725,1225847,36190392,1321228654 -8/8/8/2Kpk3/3n4/8/8/8 b - -,13,51,682,4091,55009,311608 -8/b3r3/8/p4P2/P6N/8/2K5/5k2 b - -,24,256,6023,58698,1347540,13603577 -8/8/8/1B2k3/8/1p1p4/8/7K b - -,10,102,947,10553,104312,1218788 -r6R/1b6/4Pkp1/pp1p1p2/Pbq5/2p3P1/3B1PP1/R2KN3 w - -,34,1238,34631,1220071,32972568,1141421638 -8/8/8/5k2/4n2p/1P6/2K4p/7R b - -,16,234,3901,59061,980256,15493205 -8/3k4/3b2P1/8/5N2/1p6/3K1b2/N4bR1 w - -,19,608,11007,333401,6489875,188826857 -3nk3/N3B3/PPp2b2/5rp1/8/8/4N3/7K b - -,25,468,12003,231027,5912261,116208712 -8/3r1k2/4n3/5P2/2p4n/2N5/6R1/1K3B2 b - -,27,746,18714,483929,12114720,302659245 -rnbq2r1/3pb3/pp3p1k/1P1p3p/3p2P1/2P3K1/4B1N1/1R2B2R b - -,29,823,22344,640150,18145173,529198142 -r7/2k2n2/Pp6/2pR3P/2P5/5Np1/4K1B1/8 b - -,19,539,8851,237741,3892251,102622730 -rb4b1/8/1pr5/p1P1P3/Pp2p3/3k3P/3P2R1/1N1K4 w - -,17,428,7297,187709,3309691,87471458 -k5nr/r2N4/8/np1P2Pp/1p1P1K1P/1P3N2/5q2/6RR b - -,29,522,16447,339764,11425203,251915333 -8/1k4b1/8/5N1R/8/3K4/2N5/4b3 b - -,24,622,13076,353720,7007680,191215863 -5k2/8/b7/1r3pP1/1p1p1n1p/1P5P/8/KR3n2 w - -,8,209,2316,60403,754921,20111570 -r1kr4/6p1/6p1/p4R2/3PP2P/1Pn5/4N3/4K1n1 w - -,26,693,15435,405444,8652645,231031042 -Q1n1k3/2rbp3/N3P1r1/p6P/8/3K1P1p/8/3R3n b - -,28,685,17824,475811,12893744,360994832 -1Q6/3P4/p7/P3pk2/n1p5/2N1b3/4BK2/7R w - -,6,112,5347,83710,3770466,57158203 -4k1B1/r7/2pQpbp1/ppP1P1Bp/PP6/3RKP1P/6P1/1N4R1 w - -,45,685,29809,432380,18828183,274139195 -r7/3k4/2qN3n/1QP1p3/2PP1p1p/K4PP1/4R3/R7 w - -,6,177,6958,190288,7255870,200139890 -8/p6k/P4n2/1p1p2Q1/q2P1R1p/7P/4N3/B5K1 b - -,19,532,8456,256363,4468458,137621895 -5k2/p5p1/1p2n1q1/2R2p2/P1N1PP1p/1b5B/1b3K1P/2q4R w - -,30,1379,33273,1527488,37571581,1710704497 -5r2/1k1n1p2/1p5b/pPp1p3/B7/2RN2RK/P7/8 w - -,31,722,22738,545016,16935625,407854821 -R7/P7/n2k4/8/3NK3/1p5P/8/5R2 b - -,9,288,2496,80645,786944,25365486 -1R6/7k/4b3/2p2P1P/1r6/R5P1/r6p/7K w - -,26,778,17459,499386,11020029,307266673 -rnbq1bnr/p1pkpppp/1p6/3p4/5P2/6P1/PPPPP2P/RNBQKBNR w KQ -,21,504,11778,302845,7748542,210794882 -8/7r/7k/8/n1R1q3/3B2K1/8/1b6 b - -,41,679,25166,483640,17659502,347644585 -r4br1/4p3/k1p2npp/PpnQ4/P5b1/2PPP1qP/5P2/RNB1KB2 b Q -,53,1796,84197,2567078,113930150,3401183860 -rn3b1r/1bq1pk2/p2p4/2p2p1p/P2P4/4P1P1/2K1NPP1/Rr1NQB1R b - -,42,1117,46577,1302119,53716386,1576433498 -1n5k/2N5/7p/Pp1p3P/P2pPR1B/4R3/b4PP1/3K4 b - -,14,480,6584,216456,3055966,98183757 -r1b1kbnr/pp1p3p/2n3p1/2p1NpB1/q7/P2PP3/1PPQ1PPP/R3KBNR b KQkq -,38,1578,57360,2253448,80316190,3057879289 -1k6/1p2B1bp/3pp2n/3Q1p1P/2pP4/2R5/4P1B1/K5R1 w - -,44,698,30976,487904,21695235,344182279 -B1k5/8/P4r2/P7/1P5P/3r3K/4N3/6B1 w - -,6,184,3795,101504,2339179,59276028 -r1bqkb1r/p2p1pp1/np2Pn2/7p/P1p5/8/RPPPP1PP/1NBQKBNR b Kkq -,31,664,20408,479246,15653896,398191737 -rk2r3/2p5/5pp1/p2PpP1p/P1P1P1Pq/3Q3B/1P2K3/RNB2R2 w - -,39,879,29846,708042,23714411,592209361 -4qb2/4n1kr/ppnpb2p/6pP/PP1P2p1/4rP2/2P1P1RN/1R1QKB2 b - -,47,981,44035,996859,43032489,1049380554 -3R4/4k1p1/8/5q2/b4P2/N3K1Pn/8/8 b - -,38,737,23973,438427,13895423,249232944 -4k1n1/2n2r2/8/1P1PB3/5P1P/2pP2r1/5KR1/1N4Q1 b - -,30,766,22223,645533,18295836,572546438 -6br/4bk2/1p2pnp1/p6p/q2p1PPP/NQB3N1/1P4BR/R4K2 b - -,31,1313,41836,1819885,58896307,2596427685 -5k2/8/4P3/8/P3P3/7N/N7/6K1 b - -,4,55,266,4090,18323,298235 -6nr/2p1p2B/nrq1b2k/1p2P3/1b4pP/3B2P1/P4PK1/1R4NR w - -,6,220,6280,235680,6894924,267062471 -rnbq1bn1/pppppkp1/6r1/5p1p/PP6/B1P2N2/3PPPPP/RN1QKB1R w KQ -,23,626,15637,424496,11391667,315704563 -3k1bnr/p4r2/nqpp2pQ/P6p/1p2P2P/1P1P1PPB/2P5/RN3KNR w - -,35,1219,39291,1314681,42857597,1412038992 -7k/7n/1p1R3P/1b1B4/4bK2/8/8/8 w - -,22,447,10450,204834,4741589,92540580 -1n1r4/p3bk2/2n1b3/8/pP1p4/5pK1/1N3P2/B3R1n1 w - -,17,684,10839,411550,7074951,260612362 -rr6/p1p2kpp/n3b3/P3PNb1/4P3/2P2PP1/1P4q1/R3K1N1 w - -,21,980,17399,813221,14308845,662255262 -1rbk1brN/pR1pp2p/2p5/2n2p1p/1p1PPP1P/8/2P1BBP1/1K5R w - -,41,1137,42865,1189630,42211094,1180807471 -1rk5/8/1p3R2/1P3p2/7K/b2Np3/P1Bn4/R7 w - -,32,619,18710,375305,11394312,241532410 -rnbr4/1pppq3/1b2pk2/pP4p1/P2Pp1np/1Q3P1K/1BPN2PP/1R3BNR w - -,31,1008,30917,1021059,31850214,1063850428 -8/2r2P2/5R2/Q7/1p2B2k/8/1b2K3/8 w - -,54,1164,54623,1145095,51191677,1056020621 -4k1b1/1Np3r1/3r4/B5b1/p1Pp1p2/P2P1q1N/8/4K2R w - -,17,755,12524,538646,9999696,417382181 -r4nk1/6bp/2p5/p6P/5pP1/8/K4B2/4R3 b - -,23,610,14596,357098,8719653,203182046 -2k5/8/K2n4/8/8/7r/8/8 b - -,25,71,1724,6924,165315,637722 -b7/8/7r/k7/3K2p1/8/7p/8 b - -,29,159,4589,22085,663902,3550678 -8/3n2k1/4p1p1/7p/1p5P/2b4r/5R2/5K1B b - -,27,578,15970,319690,8951565,179354129 -b7/8/4K3/3r3k/5b2/2p5/1n6/2r4n b - -,44,136,5896,27674,1226491,5058123 -rnNk4/5r1b/1p6/3Q2N1/1b1PPPPp/PP2B3/b6K/3B3R b - -,6,232,6484,255304,7115487,281888902 -2n2k2/3bp3/N3P1r1/p6P/1Q2K3/5P1p/2r5/3R3n w - -,45,1655,57231,1954990,64719060,2121000489 -5k2/pr1p1np1/1p5q/4NpP1/P1r1PP1p/1bp4B/1b5P/3R1K1R w - -,31,1200,35259,1383326,39181523,1553938122 -4r3/5b2/p3Pn2/P1kP4/2p4p/7N/2BK2P1/3N2R1 w - -,28,725,19458,491554,13528703,333026230 -3k1q2/3B4/3p2Nn/3P1Pb1/4pr1R/7p/8/2n1K3 b - -,29,500,15222,271697,8570330,156694951 -r1b1k2r/p1pqpn1p/Qp5b/1B1pPpp1/1P1n2P1/5P2/PNPP3P/R1BK2NR w k -,31,824,25629,738958,22996986,698849312 -6r1/8/1k6/8/3P2K1/P6R/1N6/3r4 w - -,5,155,2827,73236,1411027,35860717 -2B1k3/7N/1Q6/PN1p2P1/5b1p/1R2p2P/4K1R1/3r4 w - -,45,711,28979,461387,19097630,309368873 -r1q4r/pb1k2bp/P1p2p2/3pp1B1/1PBPP3/6P1/1P2Kn1P/1N4NR w - -,31,1034,31610,1047648,31747058,1052595446 -2b3k1/r1nN2b1/1P1P4/1P4p1/p3Kp2/P3n1PB/3N3r/7R w - -,31,1244,36555,1440992,41265364,1600025685 -1r1k3b/R6p/7P/3p4/8/pp4K1/8/8 b - -,18,336,6326,107214,2167452,35063609 -3rkbr1/5p1p/2P2n2/p3p1R1/1P3n2/pRPN3b/3B1P1P/3K1B2 b - -,44,1459,59859,1928939,77162435,2477043943 -8/5k2/6R1/2PP4/1K2p3/4q1p1/8/2r5 b - -,31,398,11462,152924,4437250,60320937 -1nq3nr/3k3p/bp2p1p1/r1B5/P3QbP1/2p2P1P/3PPKB1/5RNR b - -,39,1327,46190,1519577,55595029,1810106530 -1r4N1/r4b2/2p1k2p/P2p2n1/3PpK2/1P6/2B1R2R/B7 b - -,30,780,21367,577067,15948415,448852778 -3k2br/2p3r1/3N4/p5b1/pBPp1p2/P2P1P2/6q1/3K2NR b - -,41,802,29100,592923,21553412,448581249 -3k4/8/8/1Pn5/7B/8/4K3/1b6 b - -,4,60,1122,15630,285452,3949722 -rnNk4/4b1rb/1p6/6pp/Q2PPPP1/P3BN2/bP4K1/3B3R b - -,33,1607,53659,2500779,85195861,3859101719 -r4n2/6bp/2p2k2/p6P/5pP1/8/K3RB2/8 w - -,26,397,10098,182634,4409799,88325702 -8/7k/8/4B3/6Pb/3p1r2/R2N2K1/r7 w - -,31,831,22318,611079,16378640,457370122 -1r1qkbr1/1bp1p2p/1p3np1/p2p1p2/P1PnP3/3BBP1N/1P1K2PP/RN1Q3R w - -,40,1503,55186,2071481,76342260,2871100803 -6N1/2p5/1p6/1p3p2/1k2bP1p/7K/3n4/r7 b - -,38,181,6266,41937,1295356,9494271 -r4br1/2qb2k1/pp2p3/1PpQp2p/P1K2P1P/3B1N2/2PNP2B/R1n5 b - -,32,1096,33594,1175527,36712795,1298392077 -1r4nr/2p1p3/n6k/1p2Pbq1/1b2B1pP/3B2P1/P1N1pPK1/4R1NR b - -,39,1246,48104,1566387,61713502,2034730244 -8/4kb2/4p3/4PB1p/4P2P/1p6/3K4/6N1 w - -,15,132,1887,18785,265117,2857476 -6kr/3n3p/3b2b1/B1p1n3/P1PpP3/1p1P3K/8/1N4R1 b - -,20,474,11244,244120,6366954,134822587 -1n2kr2/r1bb2np/pp6/1Npppp1q/2BP1pPQ/PPP1PK1P/3B4/3R2NR b - -,30,922,25800,813289,24272796,781195379 -rnbqkbnr/ppppp1pp/8/5p2/2P5/P7/1P1PPPPP/RNBQKBNR b KQkq -,20,420,9328,221495,5414634,141156672 -1r3bn1/pb1kp1pr/np6/2pP1p1Q/P2PB2P/BP6/N4PP1/R4KNR w - -,42,1108,46200,1255932,52190105,1466684459 -Rn5Q/p1k5/2pPp3/1pqP4/1P1b2p1/2P5/2KRB1P1/8 b - -,5,202,4357,162891,3687624,132888339 -3B4/k7/1r6/K7/B3p1p1/8/2r5/3N2b1 w - -,16,526,8918,276892,4933895,149276208 -b7/b4N2/1k6/7P/P3p3/3rK3/8/8 w - -,3,75,831,19204,205799,4798603 -4r3/k7/1P6/8/6p1/3K4/8/r5n1 b - -,5,28,892,5233,164652,935323 -rn4r1/p2kpn1p/B1pB4/r4p2/P2b3P/5N2/1P2KPP1/R6R w - -,48,2042,87559,3392403,135906342,4972637568 -4r3/n2k4/p2p4/P1pP2Q1/2K5/P1b4N/3B3R/3B4 b - -,29,1111,25237,992656,21797271,861719226 -1n2kbr1/1bB2p1p/r5pQ/1p6/pPpP1n1q/5P1P/P3P1P1/RNK2BNR b - -,49,1362,61891,1793519,78354908,2340808850 -1b3Bkr/3b3p/8/pB1ppr2/2pP1PpP/2p5/2KR3B/8 w - -,26,617,15911,388131,9887199,247159186 -4r3/3k4/8/1RK5/5P1p/p5b1/8/1B6 b - -,25,446,9535,201130,4300643,94025668 -8/6r1/8/5k2/1N1B1P2/7p/4K2b/3R1R2 b - -,21,680,12581,413321,7611043,248511584 -q7/4k1r1/p3pnpB/7p/P1pPP2P/1r3P1B/R4K2/2B1R3 w - -,37,1564,52335,2061285,67915836,2555348205 -8/1b6/2k5/8/6pp/8/5r2/1K6 w - -,2,52,112,2892,12013,315943 -rn1qkbnr/1b1pp1pp/p1p2p2/6P1/2P5/7B/PP2PP1P/RNBQK1NR w KQkq -,35,627,22049,446838,16083804,359912236 -rnbqkbnr/1ppppppp/p7/8/8/N6N/PPPPPPPP/R1BQKB1R b KQkq -,19,380,8143,183425,4373890,109269510 -2bqkbnr/rpp1pppp/n2p4/p7/2P3P1/PP5P/3PPP2/RNBQKBNR b KQk -,26,470,13090,284308,8296635,202882781 -6k1/8/8/K3P3/1N1R3P/2p2p2/8/6r1 b - -,20,438,7513,166745,2807059,61745856 -8/5B1n/6n1/Pk3Pb1/1p1R4/5R1P/8/1K4N1 b - -,23,884,17134,627805,11855913,420977379 -8/8/5k2/2n4p/7P/1R6/3K4/8 b - -,15,285,3630,63665,755794,13361197 -rn1q1bnr/p2kppp1/2pp3p/1p3b2/1P6/2PQ3P/P2PPPB1/RNB1K1NR w KQ -,31,834,25926,715605,22575950,635681844 -2b1kb1r/rppqp2p/p1n5/5P1P/2Pp4/1N1P1KB1/PP2BnP1/R2Q2N1 b k -,28,738,22218,619339,19793987,573594693 -7n/8/1P1kN3/P6P/3p1p2/1p1P2R1/8/3b2KN w - -,25,374,8611,126614,2845132,42845828 -rnbqkb1r/pppp1p1p/4p1pn/8/5P2/7N/PPPPPKPP/RNBQ1B1R w kq -,24,694,15944,482203,11814327,368061310 -7r/6kp/p4n2/pNpP4/P1n1B1P1/2rR3N/7P/1qbK3R w - -,28,1331,29305,1357320,32409256,1476542674 -8/B7/5QRP/k7/3P4/2b5/8/1K6 w - -,34,246,9559,82057,3252268,29688690 -3r3r/p2k1pQ1/3p2pb/1pp3P1/P2p4/2nR3b/1PK4P/2B2N1R b - -,36,1185,41246,1341951,45586296,1497317803 -5k2/3P4/p7/P7/N1p1p1BQ/8/8/5K1R w - -,36,154,5995,27122,1084461,5107176 -3k1bn1/B7/r4npq/5p1r/pP2PP1P/2P5/R3R3/1N1K4 w - -,31,945,28031,912105,26445337,903548946 -rn1qk1nr/p1pp2pp/b4p2/1pb1p3/4P1P1/2PK4/PP1P1P1P/R1BQ1BNR w kq -,25,703,16923,476142,11682299,336716880 -bn1r2kr/8/7p/pR2b3/2p4p/4Pp2/8/4NRKB w - -,21,765,17262,586578,14200343,473199463 -8/4k3/1N2b3/1P1pn2P/P4pB1/1p1P1R2/6K1/7N b - -,22,520,9972,237137,4386777,105853080 -2kr2nr/p4p2/1pp1pP1b/1n5p/6b1/1BP4P/PP1N1KPR/R1B3N1 b - -,36,829,29648,727605,26386913,682098320 -4n1k1/5R1r/6Bp/ppbp2pP/3P2p1/4K3/R1P3Q1/7N w - -,44,841,33044,621103,23628799,449681607 -rn4k1/p6p/2p5/4Bp2/6PP/8/K4b2/1R6 w - -,34,633,18647,365310,9903510,202790802 -bbn4r/2N5/1q5k/p2P4/2P1BP1p/4P3/PB1K4/2R2r2 b - -,40,1303,51552,1640862,65793546,2047164430 -1r2rbk1/np2p3/1pq2pp1/P1p4p/1P3P1P/3Pn1Pb/1R1KB3/5R2 b - -,48,1270,58144,1492193,66397741,1686434236 -8/2p5/1p5N/1p3p2/5P1p/2k2n1K/8/3r4 b - -,32,161,4609,32236,863514,6709404 -1Rb3k1/8/5PP1/2p4P/8/5K2/8/8 w - -,19,103,1955,16797,324733,3191147 -2k2b2/1p5p/3pp2n/4Qp1P/r1pP3B/7R/2K1P3/6RB w - -,58,1208,61138,1340860,63198906,1430886097 -r3r3/pb1k4/P6p/2pPb1B1/1PBP2q1/6P1/1P3n1P/1N2KR2 w - -,31,1472,35700,1639240,41852651,1861802592 -8/1N6/7k/8/6Pb/3pK1B1/8/8 b - -,10,182,2124,36294,458273,7879862 -8/5k2/4N1N1/3r2q1/P1R1p3/1p1P4/7K/1r6 w - -,28,997,19921,723494,14319437,520323118 -8/P1k5/8/1p6/8/6r1/1pr4b/7K w - -,4,108,1179,34172,436594,12950826 -8/p4Q2/P6k/2P5/8/1P6/1r4RK/r7 w - -,30,452,12457,188859,5295323,88596213 -8/b7/8/p4P2/P3r2N/8/8/1K4k1 w - -,9,198,1811,41054,385798,8792959 -8/7k/6b1/8/1b1B4/4nKp1/6P1/8 b - -,27,391,9832,121044,2980538,35815729 -2r5/8/5b1k/rp6/3p2PB/1RN5/1N3K2/3r4 w - -,23,844,20081,723373,17822644,632047139 -1R6/7k/3Q3b/4P2p/PN2P2P/8/6K1/4N3 w - -,47,343,15509,124859,5458011,47211426 -1r6/n6r/3P1kp1/pP3p2/P1b2PPp/b3P3/3R1Q2/4K1R1 b - -,43,1078,41113,1118370,41372294,1181469692 -2r5/k4N2/5P1r/8/2p5/2P2K2/8/4N3 b - -,24,371,8839,134122,3231339,49392412 -r5n1/5b2/p2p4/Pk2P3/2p1P2p/1B5N/3K1QP1/3N2R1 b - -,21,745,14625,521133,10818541,386704403 -3rnb2/4p3/7p/p2k1n2/2p2r1P/2ppp2K/PB1NB3/RNQ5 w - -,27,884,23456,772046,21373773,705005691 -8/8/1k1n4/1p5P/1p4K1/1P1R3R/8/r2N4 b - -,24,591,12838,320238,6475829,167742484 -r1b1kbr1/pppnqp1p/3pp1pn/5P2/1P1P2P1/B6N/P1P1PK1P/RN1Q1B1R b q -,28,748,21677,608308,18189308,534973742 -2k5/r7/8/4P3/1NpK2RP/5p2/8/8 b - -,21,460,7806,174332,2911999,64755473 -r1b1kb1r/2Bpq2p/1p2P1p1/p4p2/P1p1n3/5N2/2Q1KPPP/R4B1R b kq -,36,1368,49282,1852766,67708654,2532058306 -8/3rk2n/3b1R2/1P4P1/2P5/p6r/6K1/4N3 b - -,29,577,16407,319050,9580962,185912310 -8/8/3R4/1k6/3b4/1K3n2/8/8 b - -,22,346,6217,100906,1765232,28821706 -2R5/8/4k3/5n1b/5p1p/r2p3P/3n4/2K5 b - -,37,515,16288,209599,6427267,81520400 -4k1n1/8/3P4/1N3P2/p1R3pb/P2K2N1/8/5r2 w - -,31,637,16451,340154,8258533,172968559 -4Q3/8/5k2/3K4/8/6B1/8/6q1 w - -,34,501,12666,214710,5133527,94367272 -2k4b/3R4/8/5N2/8/2bK1N2/8/8 w - -,32,441,13191,186705,5323211,82247827 -1r3b1R/1Bn3k1/p2p4/P1p2p2/b1KP1p2/P5p1/3B3q/R2Q2N1 b - -,38,1451,52011,1913912,68231194,2470312912 -r4qr1/p1B2k1p/1p2p1p1/2p1n1b1/3QPp1P/PP1b1P2/1R1P2B1/2B1K2R b K -,43,1415,55455,1773016,66634656,2130367239 -r1bqkb1r/1pp1p2p/p1n5/3p1PB1/2P4P/1N1P1K2/PP2BnP1/R2Q2N1 b kq -,33,1083,36667,1202592,41778587,1378964468 -k7/8/5b1N/6PP/2pNb1K1/2P1p3/5PR1/r7 w - -,23,816,17908,583524,12747383,392587087 -2k4b/P1P5/2N1p1p1/3P2rp/2R4P/6B1/bR6/3Kn3 b - -,21,869,18617,709443,15916712,572236918 -8/1b6/2k5/8/6pp/8/3r4/1K6 b - -,26,72,1833,5835,144927,690216 -1r3rk1/np2ppb1/1p3np1/2p2b1p/PPPB1q1P/3P1PP1/3NB3/1R1KR3 b - -,46,1212,53387,1391741,59661069,1569462627 -N2Qr3/8/6Bk/8/7K/1p5p/8/8 b - -,15,420,5999,174046,2492678,73747569 -3krb2/3R4/2P4n/3p1P2/8/5Nn1/2K5/8 b - -,1,28,671,16128,405989,9013261 -8/6b1/5r2/Pk2p3/7p/1KP1P3/2n1b3/2B4N b - -,36,372,12010,135981,4297511,52475032 -r6r/pb1k4/P6p/2pPb1B1/1PBP1q2/6P1/1P3n1P/1N2K2R b - -,51,1383,65212,1729359,78578981,2055853206 -8/8/8/6kp/5R1p/4P3/7K/1B4n1 b - -,5,104,626,13085,98170,2072261 -b2r3r/3n2k1/7p/1R2b3/pNp4p/4Pp2/5R2/6KB w - -,26,964,26422,951969,26645810,948140614 -1n1qk1r1/r2b2np/pp1bp3/1Npp1p2/2B2pPQ/PPPPP2P/3B2K1/3R2NR b - -,32,1088,31656,1068637,32437765,1104164257 -r1bk1b1r/pp1nqp2/2ppp1pp/8/1P1P1nP1/B1N1Q3/P1PNPK1P/1R3B1R w - -,37,1179,42303,1369731,50671313,1659320293 -rnbqkb1r/ppp1p1pp/5n2/3p4/P1P2p2/R2P4/1P2PPPP/1NBQKBNR b Kkq -,33,920,30671,880242,29878598,882105476 -2bqkbnr/2p1p1p1/rp3p1p/p2pP3/2P2PPP/3P4/PPn5/RNBQKBNR w KQk -,4,114,3637,105373,3423585,101982536 -8/2B2Bk1/4P2R/5P1K/1p6/8/8/2n5 w - -,21,119,2654,17067,386378,2803224 -1R6/3k1p2/2r5/p2r3p/1b2p3/p1PN3b/1R2KPBP/8 b - -,41,1442,49989,1639800,55703460,1751232162 -r3kb1r/1p2pppp/1q6/p1pp3n/P1Pn1PQ1/4P3/1P1P3P/RNB1KBNR w kq -,37,1403,47074,1711230,56725490,2025022915 -Q1b5/q3b1k1/pp2p3/1Pp1P2p/P1K1B2P/1n6/2P1P1NB/3r1N2 w - -,30,1075,29859,974333,27493694,861618246 -8/2N5/8/1p6/8/1k6/4K3/8 b - -,9,120,762,9426,59221,713529 -b7/b3r3/1k5N/7P/P3p3/8/3K4/8 w - -,12,224,2492,52261,594157,13465211 -6n1/bk6/5P2/4b3/3p2Pp/R2B3P/b3K3/3N4 b - -,25,669,15146,424101,10000078,277514554 -r1bk2r1/1p3Q2/pq1b4/2p1P2p/P4pnP/1PP2P2/3KN3/RN5R b - -,31,1291,37377,1415704,43538838,1556261374 -2b1kb2/3np3/P4rp1/B1pPP2p/1rP5/1N4P1/5P1P/n1KR3R w - -,29,854,22452,668104,17733401,537733986 -1q6/8/1k6/1pN5/1p1p4/3K4/3nB3/8 w - -,15,358,5524,141931,2104055,54720734 -1r4rk/1p6/n7/Bqbppbp1/P1p2RQN/6PK/2P3nP/RN6 b - -,56,1468,73406,2127541,100047354,3163712164 -5k2/2b5/8/3K2b1/8/8/8/8 w - -,6,136,776,16832,99658,2134293 -6n1/N7/3kP3/P7/5RP1/5b1p/8/1K6 w - -,21,353,7506,118872,2559364,40560725 -r1b1kb2/4p1rp/1qp2ppn/Pp1P4/2P1P3/N7/PB2NPPP/R3KB1R w KQ -,34,1306,41698,1546903,49383902,1800581308 -rnb1kr2/p2p1p1p/1p6/6p1/1bP2qP1/1PNPP2n/P1RKN2P/3QB1R1 b - -,40,858,33498,777247,30051413,756878443 -b1r3n1/p2k4/2qN3P/2P1p3/p1PP1p1p/4RPp1/1K3P2/3QRB2 w - -,39,1213,41741,1332829,46079785,1505030712 -5Rn1/6p1/7q/8/4b3/1K4k1/8/8 w - -,20,790,13163,480341,7482593,262555742 -8/4kP2/8/1P6/7P/p3b1n1/4R3/K7 b - -,14,220,3974,68203,1218445,22275449 -1rb1q3/p2p2p1/P1p1R3/1pPn1P1k/P6p/B6P/R2P3b/1NQ1K3 w - -,26,850,24225,776771,23626013,751584955 -4k1r1/6n1/1B6/2n1N1p1/ppp1bP2/b3p1P1/8/RK3BR1 w - -,3,99,2365,74875,1998471,62401115 -k1nB4/8/1q5p/3p4/3N4/3p4/6Kn/3b4 w - -,20,727,12175,418451,6870152,231882672 -rn5r/p3p1bp/B1pk3n/5pN1/3P1B2/8/PPp2PPP/R3K2R b - -,4,151,3218,109900,2613607,88592807 -6nr/p2k4/n6r/Pqbp2Qp/1p1PP2P/1P3PP1/R3N3/1N3K1R w - -,37,1038,36435,1048488,36541019,1090856044 -4r3/rkp5/5pp1/p2P1P1P/P1P1Pp2/7B/NP1K2Rq/R1B5 w - -,21,603,13804,385160,9236400,261406825 -8/8/8/1k6/4R2n/8/K7/2b5 b - -,16,279,4515,75982,1256237,20864453 -5n2/7k/6p1/4p2p/Bb5P/3r4/8/5K2 b - -,30,310,8729,95874,2605227,29304738 -2k5/8/n5N1/2P5/8/8/1K6/3B4 w - -,22,183,3681,31673,608296,5573174 -7r/R7/2n2npb/2pp2k1/P1p1b2r/2K2P2/6BP/8 b - -,38,680,24103,413835,14361077,246203440 -r1b1kb1r/1ppqp2p/p1n5/5PBP/2Pp4/1N1P1K2/PP2BnP1/R2Q2N1 w kq -,33,989,29842,940278,28520335,941841488 -4k1n1/8/2Nb4/5P2/p5p1/P2K2N1/2R5/5r2 w - -,32,844,23268,593062,15194401,379700157 -8/K7/8/8/8/1k1p4/8/6n1 b - -,12,60,708,3927,49500,288472 -rnbqkb1r/p1pp1p1p/1p2p3/6p1/5Bn1/NP1PP1P1/P1P2P1P/R2QKBNR w KQkq -,31,1036,32126,1062847,33824431,1120227365 -3r4/8/4k2p/rp6/6pP/7R/2n1K3/8 w - -,12,417,5688,186396,2589456,82067133 -2b2b1r/4k2p/r3P1p1/pp1p1p2/P1q2B2/Q1p3PR/5PP1/R2KNB2 b - -,8,303,9395,319581,10514558,367077817 -5bn1/r3kq2/5np1/1B3p1r/p1ppPP1P/P1P1Q3/1P1Bb2R/RN2K3 b Q -,38,1068,39399,1143719,42760633,1280422522 -1rbk1brN/pR1p3p/2p5/2n1pp1p/1p1PPP1P/6P1/2P1B3/1K2B2R b - -,31,1148,33919,1189326,35196697,1191222151 -1n6/rb2B1b1/1P4k1/pP2p3/2P1P1p1/1N1K2P1/1R4BP/5r1R w - -,35,1158,38021,1185826,38992962,1185133245 -1nb1k1nr/r1pp4/1N3ppp/p1b3P1/1PQp1P2/4B2P/P1q1P3/2R1KBNR w Kk -,37,1414,46792,1743435,59607454,2200115079 -8/2r1b1kB/2b5/8/3p4/2p3nr/1n6/4K1R1 b - -,42,473,19500,270394,11545286,171368296 -1n1q1r1k/1b1pnQ1p/rp1P2p1/P1p3BP/3N1p2/5R2/P3PPP1/R2K1BN1 w - -,50,1233,60605,1586242,76234277,2113189608 -5rk1/8/3R3P/1pp1Q2r/8/Ppb3KB/2N3n1/8 w - -,47,1403,56807,1664295,65510215,1912228055 -r4bnr/ppp1kp1p/2n5/1B1qpb2/1P1pP1p1/3P1P1N/P1P1Q1PP/RNB2K1R w - -,36,1458,51319,1995877,69446839,2638304812 -2r5/p2k4/2b4n/2Pqp3/p1PPNp1p/4RPp1/1K2RPB1/3Q4 w - -,38,1265,42992,1484687,49576074,1752918079 -2k5/8/2B5/8/7b/8/5nK1/8 w - -,13,171,2247,34848,445209,7351727 -2b1rb2/3kr3/n4pPp/2P1p1BP/2p1p3/NR3N2/P2P4/1R2K3 w - -,34,655,22869,495964,17435905,413324336 -b4r2/8/8/p3qB1k/2P2P1p/8/P1K5/7R w - -,29,1060,24607,879366,19405437,689990458 -q1b2bnr/2r4k/p1PN4/3Pppp1/2P4P/N2KPPP1/PB2B3/R5R1 w - -,37,1083,38434,1140892,40137457,1234921064 -B4b2/2nkr3/6pp/P3p3/6P1/2PPP1nP/1B1Nb3/R3K3 b - -,30,826,24543,660957,19956404,533917094 -1r3k2/p2p2p1/1p5n/4NpP1/P1r1PP1p/1bpq3B/1b1B3P/R3K2R b - -,48,1071,48109,1109610,50189814,1191659441 -8/3B4/1k1b4/8/2P1pN2/8/1K6/8 w - -,25,394,8219,116986,2283351,31501697 -5B2/P1k5/7P/4P1P1/2K1b3/8/8/8 w - -,19,321,6036,81297,1594277,19749657 -rn2kbnr/p2pp3/bq3p2/1pp4p/1P3p1P/P1PP1N2/4PPP1/RNQ1KB1R b KQkq -,24,649,16924,457760,12650259,349269346 -8/3k4/1b6/8/7b/8/3K4/8 b - -,24,147,3371,18626,419116,2374721 -7k/5b1B/8/pP6/P1n1PpP1/1R3R1r/4K3/2b5 b - -,27,648,18131,406096,11484967,255864371 -rb6/5b2/1p2r3/p1k1P3/PpP1p3/2R4P/3P4/1N1K2R1 w - -,26,601,14926,380530,9411099,251826813 -8/1B5n/6nR/P2p1Pbp/1p6/1k5P/5R2/1K4N1 w - -,25,486,13146,241812,6775994,122898859 -4R3/8/8/r4k1n/5p1p/3p3P/3nb3/2K5 b - -,28,379,9873,126756,3342350,42901730 -8/Pr1rN2n/2p1k2p/P2p3P/3Pp2R/1P2Kb2/1BB2R2/8 b - -,25,840,20070,688953,16704614,581016877 -r1bqkbnr/ppp1p2p/2np1p2/6p1/P7/1PP5/3PPPPP/RNBQKBNR b Kkq -,28,584,16971,392493,11647768,294068721 -4k3/8/2r5/1B2N3/P4n2/1P3PRp/K1p4P/8 w - -,26,420,10228,203740,4945955,110011751 -k7/8/8/3K4/2N1r3/2P5/8/8 b - -,15,160,2319,26421,402884,4605579 -2N3n1/7b/4P3/P1kN4/4N3/1K5p/6P1/6R1 b - -,5,175,2142,68395,968422,29848954 -r1b2r2/1p1p2k1/nbp5/pP2p1p1/P2qp2p/2B1nPPK/1RP4P/QN3BNR w - -,23,1158,27536,1327163,33923949,1587131779 -r1rb4/8/5k2/1p2N3/3p1KP1/R1N3B1/8/1r6 w - -,30,776,21947,625979,17198382,523794528 -3k3r/5R1p/8/p2p1P2/2P3n1/3K1N1N/2R4P/2b1q2r b - -,42,1042,39876,1022295,38519234,1015631678 -rn6/p2Np1rp/2pBk3/1B3p2/r2b3P/7R/1P2KPP1/6R1 w - -,50,1624,73480,2452091,102830688,3449081533 -r2b4/2r1k3/8/1p1p4/6P1/R1N2KBN/1p6/8 b - -,27,867,23435,724771,21123838,632769446 -r5r1/pkp1qpp1/8/2pPpP1p/P3P2P/6P1/1P1PKRB1/RNBQ4 w - -,30,904,27858,806385,25291360,722956794 -1b6/3NP1r1/2b5/r6P/2pk4/3Pp3/3R4/4K3 w - -,23,1034,22796,943368,21428318,836704432 -k7/4N3/P2Q4/1pr5/4r3/1p5K/1b6/8 w - -,30,916,23991,686469,17622928,501195258 -8/q7/5k2/p7/PP1rp1P1/2KP3B/2Rnp2r/4N1N1 w - -,16,586,9555,366670,6577001,258217904 -5Q2/6q1/p2bk2p/P6b/5R2/8/8/5RK1 w - -,5,177,5313,127501,4109651,102273422 -8/4k3/4p1b1/4PB1p/1p2P2P/8/2K5/6N1 b - -,11,146,1485,19313,198592,2621437 -3k4/p6r/b2pB2p/P4P1P/1b6/3p2pR/2PR2P1/3K4 w - -,21,450,9233,208336,4408391,102596180 -1B1N3k/2r5/5P1P/1bn5/3K2p1/6P1/8/4R3 w - -,26,656,14837,360132,8255184,194661240 -4b3/Q3b1k1/pp2p2n/PPp1P2p/4B2P/3KP3/8/4NN2 w - -,31,525,14677,273653,7906879,148708457 -8/6r1/8/1p1n4/3k2p1/8/8/K1R3r1 b - -,31,242,6852,72974,2074697,25485400 -5brn/1bk5/2pr3p/P1BppPpR/p1P3P1/N4QP1/R2PB3/1N3K2 b - -,21,870,18736,776317,17580063,726948202 -rn5k/3pq3/1pp1p3/pR1Q1pp1/P4P2/5N2/2NK1Pb1/2B5 w - -,42,1139,44359,1219673,45707297,1267607556 -rnbk3r/pp1pb2p/2p1p3/6qn/P7/NPPp2Nn/3P2KR/RQB5 b - -,45,788,34667,716538,30820203,707719677 -8/1k6/1B6/5Ppp/P1r4P/2q5/1R4K1/7R w - -,34,1014,28144,910268,24805254,801168316 -1n1rkb2/1q1b4/1nNpp1rp/1pp3p1/Q3P2P/PPPP4/4N1P1/1RBB1K1R w - -,42,1276,49983,1557524,59937854,1915404587 -1k4r1/1b5P/p2R4/Ppp5/1P3nB1/1P5P/1N3K2/1rBr4 b - -,43,1514,57804,1885514,69001576,2169702223 -8/k7/3K4/8/2B4b/6p1/8/8 b - -,9,143,1663,23479,311836,4262020 -n1k1q3/4Q3/3p3b/r2P1bpp/ppP1N1P1/PP2P2P/4KP2/2R1NBR1 b - -,30,1326,36039,1522310,43510151,1770402069 -4k3/8/8/2n3Qp/7P/1r4R1/8/2K5 w - -,28,463,13666,224525,6775391,111314598 -4n3/4p1n1/2k5/p6p/2B4r/r3NK2/1b6/1NB5 b - -,35,664,21813,455592,15185309,336439978 -3k1b2/p6r/1P1n4/P1p1p1pP/2P3B1/R6R/6N1/4K3 w - -,37,923,32212,718518,24275125,518147357 -bb2N2r/8/1q1n4/p6k/2P1BP1p/4P3/PB1K4/1R5r b - -,44,1420,57002,1836259,74151205,2352351046 -b1N3n1/8/4P3/P7/3k2P1/7p/8/1K3R2 w - -,24,409,9181,153496,3424847,58163532 -4n3/4p1n1/8/p2k3p/P1p1N2r/Rr2p3/1b1pB1K1/1NB5 w - -,26,923,21686,741639,17044937,578768962 -1rb1k2r/1p1qppb1/1pn1Pnp1/2p4p/2Pp3P/PN1P1PP1/1P2K3/R1B2BNR w k -,25,658,16882,472305,12524543,367063294 -rn2k1n1/p3pp1r/bqpp4/1p2P3/P5p1/1P1PN3/2PRN1P1/2K1bBQR w q -,30,1059,32491,1136985,36051366,1259900797 -r4bnr/ppp2p1p/4k1b1/1B1q4/1n1pPpp1/1N1P1P2/P1P1Q1PP/R1B2K1R b - -,48,1654,69188,2398388,98705966,3446264401 -4n3/5k2/p2p4/P2P2Q1/Pbp5/4K1B1/4BN1R/8 b - -,11,385,4026,143676,1619088,58644528 -rn2bk1r/4b3/2RpPn1p/8/pP2PPpP/p7/2KB1P2/1NN4R b - -,26,793,21712,665380,19086097,588822069 -1N1k4/6b1/P3p1p1/2PPr2p/5R1P/8/3Kb2R/n4rB1 b - -,32,783,24793,574148,18564837,433135893 -8/1B6/3p4/8/3K2k1/7n/8/8 b - -,11,153,1599,21058,226157,2989029 -5k2/6p1/pp1N2q1/1R3pn1/P2KPP1p/1b5B/2q4P/4R3 b - -,44,1059,45197,1115236,46849210,1163442786 -4k3/8/5B1P/P3P3/6P1/8/2K1b3/8 b - -,11,161,1878,28502,335630,5124319 -r1bq2nr/1p2bk2/p1np3p/4pppP/P1N5/1P3N2/2PPPPP1/1RBQKB1R w K -,30,830,24379,696711,20580774,609742683 -5bnr/p2kqbp1/nrpp1Q2/P6p/Rp2P2P/1P1P1PP1/2P5/1N2KBNR w K -,40,1114,40999,1228957,43863629,1381936652 -3qkbnr/1rp4b/p2p3p/PN2pp2/3P3p/P4PP1/5KB1/R1B2QNR b k -,29,887,25302,831958,24673551,849025094 -8/1K2Nk2/p7/p7/P7/8/1N6/7r b - -,20,322,5925,87303,1514857,22187791 -1r4nr/2p1p3/7k/1pn1Pbq1/1b2B1pP/N2B2P1/P3pPK1/R5NR w - -,31,1407,43563,1973950,61811749,2805738401 -1nq1kb1r/3bp1p1/rp1p2p1/p1p3NP/P1PP1pn1/1P2PNP1/5P2/R1B1KB1R w KQk -,35,1092,38598,1249721,44002481,1467866902 -r4Nk1/2n5/8/1B6/P2P4/KPp1QP1p/7P/7R w - -,41,682,24469,395396,14192982,233733333 -4r3/2k5/Pp4n1/2p3RP/2P5/6p1/6B1/3K2N1 b - -,26,623,13247,327669,6536601,165059106 -2B5/4k2N/P5P1/3p4/2QN4/1R2p1pP/4K3/r7 w - -,42,590,23375,302162,12043203,154973712 -rnbqkb1r/1pppp3/p7/5ppp/P1PP2n1/3QP3/1P3PPP/RNB1KBNR b KQkq -,25,833,22313,741199,20871981,700464122 -6B1/7R/1k6/1p6/2P5/5n2/8/2K1N3 w - -,27,355,9326,110096,2848712,32051406 -3b3k/8/3r2p1/p3p2p/Pr2PP1P/1R2N3/3QK1R1/6N1 w - -,40,1172,46806,1289983,51938280,1392562327 -1r1k1b1Q/pb2p3/np5n/P1pP4/1P1Pp3/B4N1p/5PP1/R1N2K1R w - -,35,897,31598,813999,29505383,769357331 -5b2/4P3/1k6/1p1pPB2/1p3r2/3K4/3n4/7q w - -,21,914,15366,606454,9781151,364188898 -rnb1kb2/p2p1p1r/1p3npp/3pp2P/5q1R/P1N5/1PPBPPP1/R2QKBN1 b Qq -,41,1233,47984,1515114,57006554,1853227999 -1N1k4/3b2b1/P3p1p1/3PrPrp/2PB3P/8/4R2R/n1K5 b - -,28,970,26915,869978,24891132,772742636 -2rk4/7p/7P/3p4/R7/2b5/1p4K1/8 b - -,24,495,13177,230041,6388458,102367284 -8/k7/7Q/4b3/8/3K1Q2/6P1/5B2 b - -,14,660,6176,278978,2658289,118860693 -8/bk6/4P1Q1/8/8/8/6P1/3K1B2 b - -,13,374,4275,127685,1467050,44701260 -8/4b2k/4P3/7p/P3P2P/2N5/5N2/6K1 w - -,17,238,4004,51783,876641,10786378 -6k1/8/1P4P1/p4r2/8/2K5/6B1/4R3 b - -,17,474,7303,190611,2879979,72623342 -k5r1/8/8/6K1/2p5/2PN4/8/8 w - -,6,102,1105,17816,188122,3018029 -rnbqkbnr/p1p2ppp/1p1pp3/8/1P1P4/8/P1PKPPPP/RNBQ1BNR w kq -,25,749,19607,590254,16320872,498313475 -2b5/1r2n2r/1Nn1k1p1/pP1p1p1Q/P2p1P1P/8/2RBP3/4KBNR w K -,35,746,26807,584179,21301637,481339674 -8/6n1/4R3/5k2/5p1p/r2p3P/3nb3/2K5 w - -,15,346,4280,103466,1271373,31855481 -4qb1r/6k1/ppnpb1np/6pP/PP1Pr1p1/5P2/2PKPR1N/1RQ2B2 b - -,45,1070,46873,1196476,51077387,1371053856 -2bqkbnr/2p1p1p1/rp3p2/p2pP2p/2P2PPP/3P4/PPn1K2R/RNBQ1BN1 b k -,32,946,30552,941946,30931405,983290289 -4rb2/1kpbp3/6r1/p1q2pp1/p1Pp1P2/2NP1P1P/PBK3B1/5RNR b - -,43,1077,43573,1047997,40524608,972896730 -7Q/3b4/1N2k1p1/1P1p1p2/Ppn2P1P/3P4/5RB1/4K2N w - -,42,637,24889,347722,13092621,181157295 -8/p3k3/P7/1N1p4/1K1P3p/7q/8/B7 w - -,10,227,2422,56081,612200,14325161 -1k4n1/b7/8/2p1bP2/R2R2Pp/p2BK2P/b7/3N4 b - -,25,703,16129,461885,10699069,311113767 -rn1qkbnr/p1pp1ppp/b7/1p2p3/4P1P1/N7/PPPP1P1P/R1BQKBNR w KQkq -,27,755,20252,576432,15928112,467701183 -3r4/p1p2kp1/n3P2p/P1r3P1/2bbP3/1P3PN1/2K1N2q/1R6 b - -,7,132,6209,116813,5463241,106885593 -8/8/8/4P2P/3k4/8/3N4/5K2 w - -,12,72,911,5405,67880,428208 -q1r3n1/p5p1/P2pR3/1pP2P1k/1B1Pb2p/7P/1RQ2N2/5K2 w - -,39,999,38119,1001344,38921711,1059712052 -8/6p1/8/qR6/2K2kn1/8/8/3b4 w - -,18,604,6552,215284,2505277,82033959 -2k5/3b4/p3Q2r/1p1KP3/2p3pP/1PP2R2/8/RNN5 b - -,17,645,10355,374110,6398708,228864843 -8/8/4k2p/rp5P/3r2p1/2R5/2n1K3/8 b - -,34,500,14686,200987,5874701,79479462 -2Rr4/p2n4/5k2/n7/pPNp1K1b/5p2/5P2/B5n1 b - -,26,466,12372,230227,6325719,120652589 -2rk4/8/1N6/4B3/2p2P1n/1n5B/1K6/4R2b w - -,37,814,28634,639400,21713725,501066403 -1b6/6kB/1P6/p5P1/P3R3/8/1K3p2/8 b - -,15,361,5674,131276,2277538,50788893 -8/8/8/1k6/1p6/2N1K3/8/8 b - -,7,100,657,8172,57960,699150 -1nq3nr/3k3p/1p2p1p1/r2b4/PB2QbP1/2p2P1P/3PPKB1/5RNR w - -,32,1387,43354,1803452,57397171,2336546911 -rn3bnr/p7/b2ppkpp/1p3p2/PPpPP3/R2B4/3B1PPP/1N1K2NR b - -,20,670,14012,468347,10575211,353120915 -4k3/8/np6/8/8/5p2/2K5/6n1 b - -,13,99,1469,8500,136757,761087 -rnbqkb1r/ppppp1pp/5p1n/8/N4PP1/7P/PPPPP3/R1BQKBNR b KQkq -,21,420,9542,219176,5372985,136179030 -b2r2nr/n2p4/6pb/p1p2kp1/2p2N1P/P4P2/4P2P/3K1B1R b - -,27,519,13766,257990,7149712,134383189 -1B6/8/4k3/1P6/8/1n2R3/5K2/1b6 b - -,6,162,2474,64100,1015228,25596706 -2N3n1/8/4P3/P2k4/6P1/1K5p/6b1/4R3 b - -,11,269,3509,81059,1211862,27372686 -r1bqkbnr/1pppp1pp/2n2p2/p7/2P5/8/PP1PPPPP/RNBQKBNR w KQkq -,22,483,11840,279425,7412572,187091201 -2kn4/8/8/4Q2p/5r1P/1K1R4/8/8 w - -,42,665,24112,382016,13099081,213100252 -2N4b/2r3k1/p7/p1p5/P7/N3K3/8/1n3R1N w - -,28,414,10283,189775,4618871,94501371 -rnb1k2r/pp1pppbp/1q1P4/2pn1Pp1/6P1/2P5/PP1BP2P/RN1QKBNR b KQkq -,38,937,34769,935668,33929504,972853064 -3k1B2/7p/7P/7r/5Pp1/2Rp4/N1Rp2K1/2B5 w - -,25,500,13296,254481,7088686,134694111 -5Q2/2kb3r/p7/1ppKP3/5ppP/1PPR4/4N3/RN6 w - -,41,690,25195,446219,16062898,294881001 -r1br4/3k2p1/2n3p1/pP3p2/Q2BP2P/1P1P2R1/2P1N3/4K1n1 b - -,26,1029,26726,1027974,27262148,1029168729 -1k6/8/P1r5/1p3N2/4r3/1p6/6K1/2b5 b - -,40,614,21907,266361,9050154,98077181 -3k4/8/1K6/4P3/1N3R1P/4rp2/2p5/8 w - -,24,356,7899,132510,2821453,52332208 -rnNk1br1/3pqQ2/bP6/p1p1p1p1/1PPPPP2/B6p/6PP/RN2KB1R w - -,40,1020,40328,1119801,43885242,1287432728 -5R2/1k2n3/3P1N2/1p6/1p1RK2P/1P6/4q3/7r w - -,1,39,791,28253,607608,20726998 -3bn1n1/8/B7/1pkp1P1p/P3p3/1P5P/2p1R3/2K3NR b - -,24,477,10009,209345,4373167,96597036 -rnbqk1nr/p3pp2/2pp4/1p4p1/2N1P3/1P1P4/P1P1N1P1/2KRbBQR b q -,42,1510,58811,2112863,80157868,2899741031 -8/1r2Nk2/4p3/p4p2/PN3Pp1/8/8/4Kb2 w - -,16,372,5337,119238,1695469,37423412 -1nb1k1r1/r1Q1bp2/3p3p/1PP1NP2/RP6/3p1P2/3p1KBq/2R5 b - -,50,1709,71896,2333106,95862825,3031020023 -5bk1/5b2/8/8/5K2/B5p1/6P1/3n4 w - -,14,289,3477,75720,899478,20017087 -6N1/4n3/4P3/P2k2P1/8/3b3p/1K6/8 b - -,25,279,5722,59710,1187954,13085073 -r1b1kbnr/pp1p3p/2n3p1/q1p1ppB1/2N5/P2P4/1PPQPPPP/R3KBNR w KQkq -,36,1148,40863,1285056,46104674,1458425385 -r1b2r2/1p1p2k1/nb6/Bq2p1p1/P1p4p/4npPK/1QP4P/RN4NR w - -,25,1143,28100,1262752,33064961,1454500780 -rnbqk2r/p2pbp2/1pp1pn2/P5p1/1P1N1P1p/3PP3/2P3PP/RNBQKB1R w KQkq -,37,1145,40822,1257007,44769565,1394056326 -rnbq1bnr/pppppkp1/5p2/7p/1P6/5N2/PBPPPPPP/RN1QKB1R w KQ -,28,603,16844,387672,11126054,273057885 -k5nr/4r3/8/np1P2Pp/1p1P3P/RP2KN2/8/1qN4R w - -,4,128,2478,78996,1598687,52700988 -8/nbk5/P7/2p5/2PpPK1b/3P4/1p5n/8 w - -,4,115,564,14375,92544,2304799 -rnbqkb1r/pp1pp2p/2p1Bn2/5p2/P3P3/5p1P/1PPPN1PR/RNBQK3 w Q -,33,834,25976,700225,21777853,619999435 -8/7k/4P3/8/P3P3/7p/N7/5KN1 w - -,12,71,1036,6871,104321,792643 -1n1K4/3b4/5B2/1kp5/8/8/3p4/8 b - -,21,249,5586,60522,1408258,15782156 -8/8/3KP1k1/8/5B2/8/8/2q5 b - -,24,258,6208,72297,1745583,20810185 -8/8/5k2/p1q1N2r/PP1rp1P1/3P4/2RKp3/6N1 w - -,24,939,19604,753644,16026136,610216588 -8/2R5/4P2k/7p/4n2p/8/6K1/1B6 w - -,25,271,6241,57264,1312557,12074236 -B4B2/3r1r2/p3N1kp/PP2b3/8/2Rp4/8/3K4 b - -,36,1211,39507,1266674,39691387,1239661233 -8/2k2r2/2N5/Pp6/7Q/1p5K/1b2r3/8 w - -,28,879,21542,659384,16204355,482071040 -2b4k/5R2/5PP1/2p4P/5K2/8/8/8 w - -,16,114,1925,16295,293745,2580223 -8/p2pkNr1/b2b3p/3p1P1P/2B3p1/P1n3R1/QrP3P1/3RK1N1 b - -,39,1417,50338,1760394,60775160,2103640084 -6k1/B7/8/8/1b6/6K1/8/1b6 b - -,21,287,6044,79493,1673552,22138986 -5k2/6N1/3R1n1p/3p2pP/pp1P2p1/8/2P1K3/R6Q w - -,42,500,19874,216797,8247664,90345991 -6rk/rp6/n7/2bpp1B1/P6N/1p3qPK/7P/RN6 w - -,18,754,13861,578135,11631715,483082411 -rnbqkbnr/1ppppppp/p7/8/8/1P6/PBPPPPPP/RN1QKBNR b KQkq -,19,511,10922,294596,7042743,195727106 -r1br4/2k3p1/6p1/pn3pR1/1Q1PP2P/1P6/2P1N3/4K1n1 b - -,32,1023,26693,845722,22174914,696910026 -5r2/3n2kp/3b2b1/B1p1n3/P1PpP3/1pNP4/6K1/1R6 b - -,40,897,33827,769904,28272675,643184062 -4k3/K3N3/p4r2/p7/P7/8/8/3N4 w - -,13,219,2999,47450,658347,10476926 -2b2b1N/7r/rp6/p1k2pq1/PpPpP3/1Q3P1P/3P4/RN2KB1R w KQ -,28,1160,29370,1133362,29375186,1107384396 -2b3R1/7k/R7/2p2P1P/6P1/r7/1r5p/7K w - -,23,616,12333,313582,6253574,157206804 -r1k5/1p3p1p/3ppn1b/4Q2P/P1p3BB/R2P1n2/2K1P3/6qR b - -,53,2019,91579,3390908,144176810,5322451827 -4r3/2N5/6Bk/8/1p1Q3K/7p/8/8 w - -,43,614,22842,306074,10753161,147045813 -8/8/4K1k1/8/8/8/8/8 b - -,5,36,185,1344,7488,51915 -8/8/5k2/p1q1N1N1/PP1rp1P1/3P4/2RKp3/7r b - -,47,934,36151,744017,28368703,600039464 -6q1/8/2P2P2/8/p5kp/8/1K6/8 w - -,8,202,1423,34885,289141,6818961 -1rb1Q3/5k2/1Nn3pn/pP1p1p2/P4P1P/3pR3/3BP3/2RK1BN1 b - -,2,90,1413,61465,1040547,45165322 -1nb1k1nr/6bp/p2p1q2/p1pP4/P1P1N1p1/R4P2/2r1PNBP/2B1K2R w Kk -,35,1415,45022,1784793,55264686,2166945125 -rnb4r/4b2k/1R1pPn2/4N2p/pP2PPPP/p1N5/3B3R/1K6 w - -,35,1001,34111,988565,33714701,998111690 -6kr/7b/1p1bpnp1/p6p/qQ1pNPPP/2B5/1P4BR/RN3K2 b - -,34,1194,37704,1397726,43778096,1689526986 -r2k1b1r/1p2pP1p/p5p1/2qpp1P1/nP3PR1/P1P4B/2NK3P/RNB5 b - -,36,655,21628,471061,15074319,363836025 -2k5/4Br2/p7/PQ6/1Pb5/3p4/8/R1K5 w - -,30,428,11514,195908,5454379,99059009 -1rr3n1/1p5k/1P2ppp1/1Pbb3p/1n3P1P/8/R3K3/8 w - -,15,527,7441,270014,3760929,138277672 -8/8/Q7/2k5/6pp/8/5r2/1K5b b - -,26,547,9621,197432,3615063,75674169 -8/6k1/1P4BR/p2b2P1/P3Pp2/8/4K2n/2b5 w - -,18,337,6391,118499,2342317,44354828 -r5r1/1bN4p/p1p1B1k1/2b1pq2/1PP5/3p4/P3P3/2BK1RNR w - -,40,1625,61570,2357404,88283537,3258704252 -q2k4/6r1/p3pnpB/7p/P1pPP2P/1r3P1B/R4K2/2B1R3 b - -,43,1479,60368,2035026,79905783,2657937848 -r2q1b1r/1p1bnk2/2npp2p/2p2pp1/2Q1P2P/2PP1P1N/PP1NB1P1/R1B2K1R w - -,34,1352,47686,1883115,67964398,2670458260 -rqb1k2r/pp1p1p2/3P2n1/2p2Ppp/1N2p1P1/Q6P/PP2PKB1/R3B1NR w kq -,34,805,27442,650803,22713912,558345256 -5b2/7r/rp2bqN1/p1k2p2/PpPpP3/1Q3P1P/3P4/RN2KB1R b KQ -,39,1212,44109,1333688,48557393,1459090071 -8/8/8/1pk5/8/4R1p1/6nr/1K6 b - -,19,303,5837,92909,1885062,29650929 -2rb4/4k3/8/1p1pB3/6P1/R3NK1N/1p6/7r b - -,32,1159,35286,1182713,37556207,1189870153 -1n3b1r/7p/5k1n/pppQ3b/3pP1R1/3P4/P1PK3B/RN6 w - -,44,643,25924,430931,16477309,302913882 -8/b3r3/8/p4P2/P7/8/5kN1/1K6 w - -,10,238,2359,54788,550382,12760319 -b5nr/n2p4/6pb/p1p4k/2p1Pr2/P4P2/2K3BP/7R w - -,19,530,9555,286674,5177826,161917222 -8/7N/8/1k6/6nP/2b2R2/K7/8 b - -,25,493,10119,198499,3769546,74821664 -8/P2n2k1/4p1p1/7p/1p5P/7r/5R2/4bK2 w - -,21,557,10617,277818,5447275,139958160 -1n4nr/p2r1B1p/1p5b/2p3kb/3pP1P1/2QP3q/P1P1K2B/RNR5 b - -,33,982,32074,944766,31946223,943012878 -1kn5/7P/pr3B2/P1p5/1Pb4P/1P3B2/1N2R2r/5K2 b - -,27,798,21551,683515,18908386,628542792 -8/r7/2k5/8/pR3K2/Pb1P4/2Nr4/8 b - -,29,584,15439,305857,8299007,159429741 -1n2kbr1/1bB4p/r3p3/1p4p1/pPpP1n1q/5P1P/P3P1P1/RNK2BNR w - -,21,949,19680,869683,18803772,817854912 -b1N1k2B/8/2r5/8/2p2p1n/p3p1PB/8/2KR4 w - -,33,658,21073,484521,15007351,368177392 -6k1/7N/P5P1/3pQ3/6B1/4p2P/4K3/2R1N1b1 w - -,52,170,8191,42676,1886948,13547725 -R7/8/8/2p3N1/2P5/6K1/4R3/3k1q2 b - -,15,304,5616,134144,2572769,62998192 -8/k7/5n2/8/1K2R3/8/2p1b2P/8 w - -,19,454,8316,186842,3281172,73425379 -7r/5k1b/1p1bpnp1/p6p/qQ1p1PPP/N1B3N1/1P4BR/R4K2 w - -,44,1865,82009,3211273,143290847,5403687927 -7r/n7/p1k3B1/P2r4/1P5P/1PB5/N6K/8 w - -,26,737,17639,470032,11047506,288276808 -r2nk1nr/p3p3/b1qp1p2/1pp3bp/1P3pPP/P1PP3B/4PP1R/RNQK4 b kq -,33,739,25045,612529,21085951,546511390 -1nbq3k/2ppnr1p/rp1b2p1/P4pB1/2PN3P/5R2/P3PPP1/R2QKBN1 w Q -,42,1232,50768,1559221,65113441,2080429883 -k4Nr1/r7/2P1K2n/1p1P2Pp/1p5P/1Pq5/8/5R1R w - -,23,955,19911,759721,16348514,598010490 -4k1n1/2n3r1/8/1P1Pp3/3B1P1P/2pP2r1/5KR1/1NQ5 w - -,32,995,31119,943379,30286802,902870102 -8/4k3/2P5/5p1p/3N4/8/8/B6K w - -,13,98,1636,10666,194666,1257342 -r1bqkbnr/ppp4p/3p1p2/4p1p1/Pn6/1PP4N/3PPPPP/RNBQKB1R w Kkq -,21,708,15656,526284,12861288,433306467 -3k4/2r5/6n1/8/N1pn1PB1/8/1K6/4R2b w - -,33,1025,28778,878377,23430168,704525738 -8/8/1k6/8/6pp/8/3r4/2K4b w - -,2,48,214,4681,20692,432465 -1r1q1bn1/3Qp1kr/5p1p/pp1P3P/Pp2b1p1/2N2PP1/2RP2B1/1NB2RK1 w - -,38,849,31308,773014,28932037,765037170 -1k6/bb5r/7p/B1P4P/4p3/Pn6/3PK2N/R7 b - -,22,469,11027,231591,5765027,121853424 -1nq1k2N/8/r2P4/R3KP1p/1P6/2Rp1P2/8/5B1q b - -,30,745,24410,580826,20273942,471612843 -r3q2r/pkp2ppp/1pn2N2/2bPp3/P3PP1P/6P1/1P1PK1B1/RNBQ1R2 w - -,35,1354,47361,1772284,63008927,2308455806 -2b1kb1r/r2p1ppp/ppn2q2/Q1P1pP1P/2P5/4P3/P2P1K2/RNB2nNR w k -,29,1095,31331,1162455,34173215,1258550098 -8/7k/4P3/3Qb2p/P3P2P/2NN4/6K1/8 w - -,35,513,18772,227077,8142597,91960138 -1k6/qN3n2/8/Q1PPp1r1/1KP2R2/5Ppp/8/6R1 w - -,35,756,22664,524984,15944039,389489602 -r4bnr/ppp2p1p/4k3/1B1q1b2/1n1pPpp1/3P1P2/P1PNQ1PP/R1B2KR1 w - -,30,1197,36412,1446904,44908685,1781871764 -3kr3/6rp/p6P/npp1p3/2Pp4/P3bK2/RP6/N4BNQ w - -,20,692,14654,473317,11292722,353089463 -8/6R1/8/8/k5PP/2Kb4/8/8 w - -,16,203,3537,39090,706790,7908503 -6N1/6k1/P1B1P3/1p3b1K/1B4P1/n7/7R/8 w - -,38,510,16009,222463,7022840,99255106 -1n3k2/8/2bn4/B1p4K/P1PpPb1N/1p1PR3/8/8 b - -,31,575,16293,318116,8748463,177736343 -5n1k/8/2B3p1/4p2p/7P/4bK2/8/8 w - -,13,233,2960,49162,629199,10365805 -rnbqk2r/p2pbpp1/1pp1pn2/P6p/1P1N4/3PP3/2P2PPP/RNBQKB1R b KQkq -,29,1035,30967,1106461,34094093,1224694190 -8/2k5/1n3B1p/P4prP/5R2/3P4/4NK2/2b5 w - -,30,666,17971,410455,10805802,251769736 -8/k7/P7/2p1N3/P1P2p2/8/6K1/6R1 w - -,21,96,2120,8799,194676,915926 -8/k7/5nb1/8/1K4R1/8/7P/2b5 w - -,19,531,9177,232447,3946166,96400811 -r2n3r/1bp3pp/1N1k2Pn/pP3p2/1b1ppq1P/BP3P1R/2PPPK2/1Q1R1BN1 b - -,40,925,34689,851149,32863577,849634215 -rnbqkb1r/1ppppp1p/6pn/p1P5/6P1/8/PP1PPP1P/RNBQKBNR w KQkq -,23,457,11886,270161,7696588,193001780 -8/3b4/4k3/8/3p1b2/B5p1/6P1/3RK3 w - -,15,298,4707,93821,1608904,32078229 -5b2/1q3b1N/1k1Q4/2p3p1/2Bp3P/P1P3P1/2NK1P2/2r1R3 b - -,4,208,7178,318006,11043563,460324563 -1R2Q3/r7/2b2kp1/pp1p1p2/Pb3P2/1q4P1/2pB2P1/R1K1N3 b - -,35,945,23525,669484,17581567,519703742 -qBn4r/1b5k/3b4/pN1PpN2/2P4p/4PPp1/P1B1K3/B3RR2 b - -,26,1045,24875,980245,25648604,1002083991 -6k1/1b6/1K1R4/2P5/8/7p/8/8 b - -,15,265,3337,60314,779482,13939159 -1N4Q1/8/3k4/3N4/3pbr2/3P3K/4Q3/1R6 w - -,57,1003,46573,782180,36828642,616975077 -1r2kq2/6r1/p3pnp1/2p2B1p/P3PB1P/1P3P2/R1KP4/2B1Rb2 b - -,43,1306,52800,1597686,63077020,1911272836 -1B1k2n1/2r3b1/3q2p1/3R1p1r/pPN4P/2P3n1/8/2RK4 b - -,37,771,27001,613078,22005639,534468814 -3N4/3b4/3p1P2/8/5kn1/6nR/1K6/7q w - -,18,684,11913,430197,7563253,265993740 -8/6k1/8/4K3/8/8/8/8 w - -,7,52,385,1994,14904,90662 -r7/7k/5b2/1p6/2Np2P1/1R4B1/5K2/1r6 b - -,38,968,33837,840135,27718872,687688729 -7R/7b/k4P1N/7r/1Np2K2/2P5/3r4/8 b - -,5,115,3712,78314,2404354,51644430 -8/8/q4k2/p5r1/PP1rp1PN/1KnPp3/R2N2B1/1R6 b - -,44,1262,51858,1450959,59987641,1677193062 -rk3bnN/q7/1p1p4/1b1Pp1pp/1pn1Pp2/2B2PPB/R2NK3/3R4 w - -,39,1336,43971,1513183,49874268,1749217239 -1Nk3nQ/7p/4pppb/3rq2P/2pPP1P1/1b3P2/P4K1R/2B4R w - -,34,1178,37646,1306811,42995408,1493274130 -6b1/2r1k3/1pB1P2N/P4P1K/6P1/n7/8/4BbR1 b - -,25,704,16745,460687,11340505,315707386 -8/8/8/8/2k4n/5R2/K7/2b5 b - -,16,246,3980,61721,1021486,16103204 -1k6/6N1/Pr6/1p6/2r5/1p6/6Kb/8 w - -,11,334,3241,96213,967819,28836173 -4kb1r/4p1pp/2p2p2/p1p1PP1n/2PP3q/4n2N/1rR1K2P/1N3B1R b - -,39,660,25057,462933,17406380,345864038 -3k1qn1/8/3p2N1/3P1Bb1/4pP1R/7p/4r3/2nK4 b - -,31,519,16967,310503,10417105,195918539 -2kN1b2/2n5/3p4/3Pqbp1/prP1PPPp/N6P/p4K2/3R2RB w - -,32,1390,40062,1688989,47729045,1973565059 -6k1/5b2/3n4/pP3B2/P4pP1/1R2PR2/6K1/2b4r w - -,26,816,19557,597917,14454325,435414384 -3qkbnr/2p1p1p1/rp3p2/p2pPb1p/2P2PPP/n2P4/PP2K1BR/RNBQ2N1 w k -,38,1280,45834,1533685,54788302,1840772832 -8/r7/8/k1N5/p2P1K2/P7/b7/Rr6 w - -,19,513,9344,253634,4685175,128342079 -r1bNk3/p2p1r2/n2b3p/1B1pp1pP/3B1p2/P3P2R/Q1P3P1/R3K1N1 w Qq -,46,1212,53530,1362333,59706578,1516578315 -3qkb1r/1ppbpp2/r1n2np1/p6p/1P1p2P1/B2PPP1P/P1PN2BR/R2QK1N1 b Qk -,34,977,34970,1018012,37693349,1117948621 -8/1pr2k1p/7n/4pbp1/2pB4/2R3PN/1K4BP/6R1 b - -,30,1073,28799,1052277,27688478,1022767595 -2B1k1n1/r4pr1/n1p5/1pbPp1q1/Pp5P/N1PPBP2/2Q5/2R1K2R b K -,43,1901,80316,3458024,146155933,6168807989 -1b6/5br1/rpk3N1/p4p2/PpP1P3/2RB2RP/3P4/1N3K2 w - -,28,724,20153,546153,15182580,423952181 -k7/8/1b5P/1b6/8/r7/4p3/4KN2 w - -,6,198,1387,43455,347093,10731613 -5k2/1N3r2/p4b2/p1p5/P7/N1n4P/5R2/5K1N b - -,27,596,14849,320677,7911417,177764097 -R7/7p/2K4P/6kP/1rp4n/5pB1/8/8 w - -,28,451,11142,202485,4766761,92192495 -8/R7/6R1/2p3K1/1qP5/5N2/8/3k4 w - -,37,592,19654,369215,11118367,214521645 -1n1qkb1r/1b1pp1pp/8/1pp1Pp2/rP1P4/pB3N2/PBPN1PPn/2RQK2R w Kk -,32,1041,33358,1083554,35885598,1178243911 -8/1R4p1/8/q7/2K3n1/6k1/8/3b4 w - -,15,556,6279,224598,2654550,92789730 -3Nk3/p5r1/b2p3p/5P1P/1bBp2p1/P5R1/QrPR2P1/4K1n1 w - -,32,914,27140,778681,23774574,687882762 -8/8/1Pk5/5p1p/3P4/b7/7r/B1N2K2 b - -,25,233,5311,57364,1258452,15547110 -8/r7/8/1k2N3/p2P4/Pb4K1/8/R6r w - -,22,726,14541,448014,8837116,263668710 -2k4b/2P5/2Q3p1/6rp/3p3P/1R3nB1/2R5/3K4 w - -,50,770,36072,584433,26002195,448993416 -rnbr4/1p5p/4p1kb/p1P1n3/P2QpPPp/2P1N3/4P2B/1R2KB1R w - -,39,1141,40948,1150629,40807620,1151088008 -rn6/p2pq1p1/1pp1p1k1/4Rp2/P4n2/N3Pb2/3K1PB1/2BQ2N1 b - -,37,1079,36924,1124521,37403301,1180333925 -R2Q4/8/p6k/P7/N7/7B/4p3/4K3 b - -,4,148,523,19406,81559,3019611 -r1b3r1/p2p1pk1/np6/4q1p1/N1P2RPp/1P1PP3/P1RK3P/1QN1B1n1 b - -,44,1087,42084,1086203,41185645,1114012422 -bk6/b7/7p/2P4P/1B2p3/P7/3K3N/6r1 w - -,11,244,3123,67616,966024,21536955 -r2k1b1r/p3n3/1p1B1q2/3b1p1P/PpPp4/2Q5/3PPP1P/RN2KBNR w KQ -,39,1530,57196,2238341,81922447,3214305391 -2b5/8/2n2r1k/P2p1p2/1p3PPp/1P5P/2K5/4R2n b - -,23,499,11477,206948,4864452,81310483 -2qk1r2/1pN2pbp/3ppn2/P2n2p1/P1p3B1/3P4/1BQ1P2P/R3K1NR b K -,32,1316,42252,1693983,55906269,2219681549 -b2b4/5r2/7k/5K2/8/2p5/1n6/6rn w - -,2,104,304,14526,44480,2069919 -5k2/2B5/r7/1p1pp1K1/R7/1n4Pr/1p4NP/1N4b1 w - -,28,1048,25792,933062,22890658,817119920 -8/2r5/3NN2k/p4p2/P4Pp1/2K5/8/8 w - -,8,125,2289,30910,544055,7498026 -5k2/8/1P6/p4BP1/P2R4/6b1/1K3p2/8 b - -,16,520,8736,243766,4338007,110707280 -N2q2nr/1p2b3/7k/5Ppp/pp2B1P1/B1P4P/P2pK3/3R2NR w - -,30,859,24822,750929,21123307,669177340 -q5n1/p1r2R2/P2p4/BpP2Ppk/3P2bp/7P/1R3N2/1Q4K1 b - -,31,1193,34165,1356787,38789781,1557714310 -6b1/1r1Bk3/1p5N/P2nPP2/4b1P1/6BK/8/5R2 w - -,30,678,18536,454097,12547181,322662808 -rnb1qbnr/p1pkpp2/3p2pp/1pP5/2N5/4P3/PPQP1PPP/R1B1KBNR w KQ -,37,799,29496,673655,24832541,597611031 -2b2kn1/r7/1n1P4/NP3Pp1/p5N1/P3K3/1r6/2R1b3 w - -,26,1041,23064,869157,19253129,702643921 -r1bqkb1r/p1p1pnpp/1pn5/3pPp2/6P1/2N2P2/PPPPQ2P/R1B1KBNR w KQkq d6,34,976,33659,987048,34510101,1039133404 -rnbqkb1r/ppppp2p/5p1n/6p1/1P4P1/2N2N1P/P1PPPP2/R1BQKB1R b KQkq -,20,504,11213,299815,7223917,203938408 -b2n4/6b1/P1pBkP2/8/pNP3P1/6p1/3R4/1N2K3 w - -,34,434,14687,208758,6828216,107079492 -2k2r2/6p1/4P3/r5pP/1P1P4/7N/n2K4/8 b - -,30,421,12241,165001,4667154,63083594 -1Nk3n1/6Qp/4Pppb/6PP/2p1P3/5q2/b2r4/1RB1K1R1 b - -,41,1167,39014,1116594,36602767,1084763937 -rnbqkbnr/pppppp1p/6p1/8/8/3P2P1/PPP1PP1P/RNBQKBNR b KQkq -,21,586,13623,387170,9861676,287832883 -rn2kbr1/pb2pp2/1N4p1/1qp4p/2PP1P2/PQ2P3/RP2K1Pn/2B3NR w q -,30,1058,30873,1092321,32649399,1169172915 -5r2/3rk2p/p6P/1pp1p1K1/1PnN4/P6Q/R7/N4Bb1 b - -,41,1530,52977,1891827,62847311,2200230647 -2b1kb2/1r2p1rp/2p3pn/P2PP3/2PB4/N5P1/p4PBP/R1N1K2R b KQ -,28,993,27622,967837,26915001,936952912 -8/3b4/1N1k4/1P1pnBp1/P4P1P/1p1P1R2/8/5K1N b - -,21,582,11115,296980,5538538,146233987 -2r4r/4p3/b4Pk1/2p5/R4PpP/4b1PN/6K1/1q5R b - -,58,1141,57474,1213332,57817209,1291058928 -1N6/8/P4RP1/3B2rk/7P/3p4/6N1/K1b5 b - -,15,428,7360,199506,3650468,97958634 -1r1q1kr1/2p1p1bp/1pb1B1p1/p2pP3/P1PnN3/1PK1BP2/6PP/RN1Q3R b - -,32,1540,49050,2254043,71761494,3187519295 -r5kr/1b2p3/1Nn2ppb/pPpP1Q2/5P1p/P3PN2/RP4Pn/2B1K2R w - -,44,1374,57051,1759436,71307660,2189388414 -3k4/8/1n6/1P1P4/3Pn2P/2p3R1/5KQr/1N6 w - -,6,138,3533,81529,2161138,49188017 -1rb3r1/p2p1pk1/1N6/4q1p1/1nP2RPp/1P1PP3/P1RK3P/1QN1B1n1 w - -,28,1313,35352,1560464,43362599,1855902968 -6b1/5kP1/8/1P3B2/3B4/p7/4K3/4R3 w - -,37,155,5643,51581,1786586,19083864 -2k1N3/8/r7/1PNP2pP/6p1/5r2/nK6/8 w - -,19,549,9244,245377,3898537,100692125 -6nr/2p1p2B/nr2b2k/1p2P3/1b4pP/3B2P1/P1Nq1PK1/4R1NR b - -,36,1152,45195,1408784,57123858,1775740563 -3K1k2/8/8/8/1P2n1p1/2r5/p1N5/5N2 b - -,28,304,8265,97437,2652713,33935206 -8/p7/P2q4/5k2/N1KP3p/8/1B6/8 b - -,30,317,7899,92037,2230410,28307195 -rnbqkbnr/1p1p1ppp/p1p5/4p3/P7/1P6/1BPPPPPP/RN1QKBNR w KQkq -,26,778,20611,621649,17065425,525950400 -8/1B5k/7P/1b1R4/8/7K/8/5n2 w - -,20,291,6423,93158,2046961,30075646 -8/7p/2bb2kP/p2pr3/2p2P1r/1Bp3p1/2R5/3K2B1 b - -,39,808,29832,609159,21643213,441126210 -5bn1/7r/2r1kp1p/pp1p3P/PR4P1/N1p2P2/3P2BK/2B2R2 b - -,32,914,25944,722601,19911692,554202906 -2k5/1p2B1bp/3pp2n/r2Q1p1P/2pP4/2R5/4P1B1/1K4R1 b - -,26,1027,23175,942285,21563228,886119107 -2kr1b1r/1b1pn3/2p1p2p/P4pp1/p2BP1P1/N4QP1/2PP4/RN3BKR w - -,47,883,39781,834158,36360122,827172568 -k7/1r6/p1QB4/Pp6/1P1p4/3K3b/3r4/R7 w - -,2,27,946,14945,518889,9894646 -4kr2/4r2p/7P/ppp5/1Pnbp1K1/P7/6R1/N4B1Q w - -,27,1059,27859,1046851,29165803,1057727363 -8/8/P1pnk3/4b1pR/1P3r2/6N1/2NBK3/8 b - -,35,958,30742,872153,26820789,779404085 -7k/5R2/3N3B/1p1pP2P/P7/1b1pn3/3K1PP1/8 b - -,16,500,6625,198041,2532053,72244174 -8/8/3k4/1p4r1/2nK2p1/7R/8/r7 b - -,37,572,18934,255584,8228446,111087822 -rnbq3r/p2p3k/1pp2p1p/1PbNp1p1/3PnN1Q/P6P/2PB4/R3KB1R w KQ -,43,1457,61820,2074858,87197603,2914976379 -r1b5/p2pkNr1/3b3p/1n1pp1pP/2BB1P2/P5R1/Q1P3P1/2R1K1N1 b - -,29,1339,38500,1713599,49202419,2144309671 -4k1r1/1b1n4/1B2n3/1p1r2p1/pbpp3p/P3PPPR/3N1N2/R1K2B2 b - -,40,1283,50432,1612858,62941769,2023866146 -8/4kqr1/p3pnpB/7p/P1pPP2P/1r3P1B/R4K2/2B4R b - d3,34,1140,36312,1206620,39031027,1279785036 -4n3/4p1n1/2k5/p6p/r1p4r/R3pK2/1b2B3/1NB2N2 w - -,22,694,14947,461508,10481638,323546739 -rn4r1/p2k4/b1p3pp/qp3p2/1P2PpP1/1PN3nP/P1KP1R2/R1B2B2 b - -,33,1040,33223,996884,31433605,917569118 -4k3/3b4/7P/P3P1B1/6P1/3K4/8/8 b - -,9,141,1631,26357,304326,4938496 -3kr1b1/2p5/5b2/pN2ppP1/p1P4r/P2P1PR1/2K5/B3qBNR b - -,44,972,40543,943709,37988374,926499215 -1n1q1b1r/1b2pkpp/8/1pppPp2/1r1P2n1/NB4P1/PBPN1P2/2RQK1R1 b - -,37,1078,37540,1127701,39170425,1219481595 -2b1k3/r2p3r/nP1Pp1p1/5P2/pP3Bn1/3K1NP1/P7/bN3BR1 b - -,39,1161,42033,1244777,43002065,1290217639 -5k2/n7/p2p4/P2Pb1Q1/2p5/P3K2N/2B4R/4B3 w - -,45,598,23807,306192,12163995,158709034 -b1k3r1/6N1/p1p2RP1/Pp5P/1P1r4/1Pn2B1P/8/1rB1K3 w - -,22,664,15091,453000,10859205,326187022 -b3r3/2kn2r1/p1p3P1/Pp5P/1P1N3R/1P5P/3BK1B1/1r6 w - -,7,237,5357,175693,4292113,139744737 -1Q2k3/8/8/1P1P4/3P3P/8/2n1K3/1N6 b - -,3,84,629,16385,122963,3289296 -2b1kb2/r3p1rp/2p3pn/Pp1P2B1/2PqP3/N7/P4PPP/R1N1KB1R w KQ -,30,1290,34755,1433399,39909238,1592862781 -3nQ1b1/7k/4p3/4P2p/1p2P2P/5B2/4K3/2N5 w - -,26,180,5028,41125,1171480,10826166 -8/3k4/n4P1p/1p4p1/7P/8/2r2RK1/r7 b - -,38,408,13073,177984,5507205,83658944 -8/6b1/8/3bk1P1/2P5/1p4p1/1NN1K3/6R1 w - -,27,556,12716,246385,5460992,106992903 -8/7Q/1P3k2/3P4/1n1P3P/8/4K3/1N6 b - -,6,174,1009,25593,177226,4768173 -r1k2b1r/1q1b1Np1/1p1p4/n3p2p/1pPPPpn1/RNB3PB/4KP2/5R2 b - -,40,1505,57999,2141267,82618867,3015031850 -1n1B4/3k2K1/8/2p5/2Pp4/8/8/5b2 w - -,15,206,2554,36785,442547,6862052 -2b1kbn1/r1pqp3/n2p3p/3P1pp1/ppP3P1/PPB1P2P/Q4P2/RN2KBNR b KQ -,23,685,17480,532817,14672791,460241394 -8/8/r1Nk4/PB6/8/1P3PRp/2K4P/8 w - -,30,290,8451,95243,2817722,35264741 -2r4r/4pk2/1q3PB1/2p5/R4PpP/3bb1P1/6K1/6NR b - -,6,152,7277,171569,7822919,191086866 -8/2N5/8/1p6/8/2k5/4K3/8 w - -,12,84,996,7043,83303,543409 -r1b2r2/1ppp2k1/nb2p3/pP4p1/P2qp2p/2B1nPPK/QRP4P/1N3BNR b - -,42,1033,43072,1133069,47837258,1324395277 -rBb1kbnr/p7/1p6/3p1p1p/PpP4q/7N/3PPPPP/RN1QKB1R w KQkq -,26,969,26990,1007791,30138364,1130678730 -rnb2br1/p1ppkp1p/1p6/1N1q2p1/2P2BP1/1P1PP2n/P6P/R2QK1NR b KQ -,41,1279,48630,1503346,56412502,1764593938 -rnbqkbnr/1ppppppp/8/p7/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq -,21,629,14663,447202,11405790,359371776 -3rk2r/2p1ppbp/n5pB/pp1p1q2/1P1Pn1b1/P1P2Q2/3NNP1P/1R2KB1R w - -,34,1523,54320,2374473,85456804,3661659186 -r1bqk1n1/p2p1pp1/nprb4/2pNp3/1P1P2Pp/4BP1B/P1P1P2P/RN1QK2R b KQq -,28,1025,28279,1019226,29202185,1042243047 -rnb1kbnr/pp1pp1pp/1q3p2/2p5/4P3/2P4P/PP1P1PP1/RNBQKBNR w KQkq -,30,800,24064,663918,20153375,572235963 -1rb1qbn1/ppppp1p1/8/P2r1k2/P6p/B1PB1P1P/3PQ1PN/RN3KR1 b - -,4,120,2927,94162,2397909,79478306 -rqb1k1r1/pp1N1N2/3P4/2Q2P2/4p1Pp/P3n2P/1P1BPK2/R4B1R b - -,23,1020,23274,1004628,24400743,1018954430 -bnR4r/3k3p/2p5/p1Pp1q2/P7/3p4/3P3n/1NB3K1 b - -,31,347,9777,123602,3585763,49312726 -2r5/n3b3/5kp1/pP1P1p1r/P1bp1P1p/B3P1Q1/5KPn/R5R1 w - -,30,1012,28168,964091,27459552,947592777 -q5n1/p6r/P7/BpPp1Ppk/3P2bp/7P/1R3N2/1Q4K1 w - -,35,842,29638,760543,26655519,713996117 -1k6/4b3/p2p2Qr/Ppp2pP1/4R3/R2K3b/1P2r2P/2B5 w - -,36,1019,32017,906071,27994161,786522596 -5bn1/7r/1r2kp1p/pp1p3P/PR4P1/2p2P2/3P2B1/1NB2RK1 w - -,25,700,17333,461038,11768666,309239719 -rnbqkbnr/ppp1pppp/8/3p4/6P1/5P2/PPPPP2P/RNBQKBNR b KQkq -,27,541,15438,338556,10132901,239760596 -3k3r/2R4p/5n2/p2p1P2/2P1N3/3K3N/2Rp3P/2b4r b - -,28,787,21237,586949,16198634,448588419 -rnq2Bnr/3k3p/1p2p1p1/8/P4bP1/2Q2b1P/4PKB1/3r1RNR b - -,53,2043,89897,3104258,136987678,4616426254 -k5N1/5n1p/P1bq4/3p4/7B/3p3K/8/5n2 w - -,13,471,5551,199924,2538920,90083483 -2Nk4/5r2/7P/1P1n2p1/8/4r1p1/2K5/8 b - -,39,393,14022,141087,4652254,48401336 -5B2/1r2r3/p3Nbkp/PP1B4/4P3/2Rp4/8/4K3 b - -,26,765,20361,600495,16057771,476366213 -1r6/6kN/nP3b2/2R1P2P/3K2p1/6P1/4b3/4R3 b - -,28,724,18883,492102,12945429,338534416 -1k6/8/5pP1/p1p5/PPP5/7K/N3Rr2/R7 b - -,15,353,5550,133366,2127725,51938398 -5k2/1n6/P1p2b2/6p1/1P6/N7/3B1r2/3K1N2 b - -,28,502,14735,272058,7859477,151614377 -r3B1nr/ppp2p1p/4k1b1/2b4q/1n1pPpp1/1N1P1P2/P1P1Q1PP/R1B2K1R w - -,33,1214,40812,1529900,52042399,1972007926 -2N3n1/8/4P3/P2k4/6P1/7p/1K4b1/4R3 w - -,26,294,6978,98365,2259399,35265390 -4k3/2r4B/p4n2/prpP2P1/P1n5/2N4P/1b2N3/4KR2 w - -,31,1068,31591,1034595,30051343,967904490 -6k1/8/5K1P/1B6/8/1n6/8/4R3 w - -,30,243,6651,50050,1287645,9615433 -3qkb1r/1rp1n2b/p2p3p/PN2pp2/3P4/P4Pp1/6B1/R1B1KQNR w k -,31,795,26451,734297,25602778,753465554 -2r1k1Br/2p4p/4pbp1/ppP1P3/P3bB2/1PN1QP1P/3K2P1/3R2R1 w - -,38,1019,39081,976763,38290606,929486513 -2b2bnr/r3pk2/p1qp1pp1/1NPP3p/2P4P/N3P1P1/P2K1P2/R1BB2R1 b - -,33,989,30597,909645,28074639,832402498 -4kr2/3r3p/7P/ppp1p1K1/1Pnb4/P7/6R1/N4B1Q b - -,37,853,30432,818571,28274450,818905213 -1n1q1b1r/1b1ppkpp/8/1pp1Pp2/rPNP4/pB3NP1/PBP2P1n/2RQK2R b K -,39,1179,35951,1150678,36283529,1207904939 -8/3k3p/8/rpn2Pp1/7P/5K2/4r3/5R2 w - -,14,506,7304,252258,3745555,124957728 -bnk5/7p/8/R1Ppq3/P4r2/3p3K/2NP3n/2B5 b - -,49,666,29741,430258,17836183,277644857 -1k6/4N3/6P1/7n/1b6/8/8/q5NK b - -,36,298,9418,98381,3272603,37443259 -2K5/8/2k5/7P/3b4/1b6/8/5R2 w - -,17,415,6291,139788,2136376,45176620 -4r3/5r2/1q3k2/p3p3/PB1Q3p/1PnPppPN/1RKN4/5B1R w - -,39,1482,57365,2157199,82324145,3084141924 -7n/8/PP1kN3/7P/3p1pR1/3P4/1p6/3b2KN b - -,19,457,8773,192696,3674660,80575180 -6nr/1k5r/2n5/Pp1pN2p/Rp1PP1PP/1P6/7q/2N1K2R w - -,23,852,17151,616069,12956006,462149478 -1R1r4/p4k2/1N6/n1n5/1P1p1K1b/p4p2/1B3P2/6n1 b - -,41,758,26601,488481,15909004,299703497 -rn2qbkr/1b1pp3/p7/2p2p1p/P1pP2p1/1P2P3/N1K1NPPP/R1Q2B1R b - -,30,845,26365,772979,24720902,747774285 -b3nbr1/2qnp1p1/1Bk3B1/3pP2p/P2P4/5P2/Q1r3p1/4K1R1 w - -,27,739,18953,537978,14426581,425399068 -q1r3nr/4p1k1/8/1bp1P3/4BPpP/4b1P1/1R5K/6NR w - -,29,1276,32245,1413398,35289421,1546336433 -r7/4n2k/1pQ1p3/p2N1p2/Pp3Pp1/7b/4NK2/8 w - -,31,724,21337,456216,13190459,278535020 -2B5/5k2/5r2/6bn/b1np3r/2p5/2R5/3K4 w - -,9,374,3964,167257,2188470,93840331 -R1b2R2/7k/8/2p2PPP/8/8/6rp/r6K w - -,2,42,863,15507,323820,5973924 -rn2b2r/4b2k/2RpPn1p/8/pP2PP1P/p5p1/2KB1P1R/1NN5 b - -,30,850,26673,767289,24862066,725605846 -k7/8/5b1N/7P/2p1bKP1/P1P1p3/1rN2PR1/8 w - -,18,591,10796,339525,6547572,198379269 -1rbk2r1/1p6/pq1b4/2p1PQ1p/P4pnP/1PP2P2/3K4/RN4NR w - -,34,925,29977,883996,27574421,858989625 -5k2/2R2bp1/8/pp2Kp2/P3PP1p/3R2qn/3N3P/6q1 b - -,45,1355,54062,1495464,58673222,1536873330 -3r3r/8/1k6/8/6p1/8/4K3/8 b - -,32,133,4282,19687,628526,2925706 -1B3b2/r4r2/nP4k1/1PN1P3/6pP/3bK1P1/8/4R2R b - -,39,1073,38514,1064834,36946741,1035030340 -4rr2/pppk1n1p/3b1p1n/Q3p3/P2p1Pq1/BP4P1/R3P2P/1N2Kb1R w K -,35,1550,50920,2168466,71097032,2963727047 -2Nk4/4r3/7P/1P1n2p1/8/6p1/1K6/4r3 w - -,10,363,3612,118116,1235124,38641485 -8/8/3k2r1/1p6/2nK2p1/5R2/r7/8 b - -,35,565,17629,249894,7728285,107897526 -4Q3/1b4k1/1N4p1/1P1p1p2/Pp3PnP/3pR3/4PNB1/2R1K3 w - -,56,865,43533,656844,31508945,476360141 -r1b1k2r/p1p1pn1p/Qpq4b/1B1pPpp1/1P1n2P1/3P1P2/PNP4P/R1B1K1NR b k -,27,828,23718,743388,22832445,730956367 -8/2k5/8/4n3/2N5/3p4/8/K4N1r w - -,11,253,2729,62982,791947,18672092 -1rb1kbr1/p2p4/B3p3/6pn/P2P2Pp/2p4P/2P1P3/RNBQ1KNR b - -,30,827,24554,688888,20470256,593724757 -r1kr4/6p1/6p1/R7/1P1PP2P/8/4N3/3nK1n1 b - -,24,572,14373,307219,8220109,167931363 -b1k5/8/8/3p1n2/P2P2pp/1Q6/1K2B3/4r3 w - -,30,594,15335,317104,8057854,170344861 -8/3r2N1/8/p4P2/Pb6/8/4K1k1/8 w - -,5,133,1017,24138,214520,4979122 -3k4/2B5/5P2/8/8/6N1/5K2/8 b - -,4,77,350,6296,32811,585932 -1kn1R1b1/7P/pr6/P1p3B1/1P5P/1P3B2/1N2K3/5r1r b - -,31,1138,36168,1277753,42168573,1452857604 -2kN1b2/2n5/3p4/3P1bp1/prP1qPPp/7P/p1NR1K2/6RB b - -,47,1206,55482,1477788,66177203,1813799545 -7k/8/pp1Qp2n/PP2P2p/4B2P/2p1P3/3NK3/4N3 w - -,44,414,16773,175344,6443168,73587898 -r4qr1/p1B2k1p/1p2p1p1/2p3b1/4PpnP/PP1b1P2/1R1P2B1/2B1K1QR w K -,26,1121,30789,1260276,36641211,1452723331 -8/5k2/6R1/1KPP4/4p3/6p1/3q4/2r5 w - -,18,587,8282,251768,3542311,106132699 -6N1/8/4P3/P2k1n2/6P1/3b3p/K7/8 w - -,11,231,2490,51628,586915,11845069 -3k4/8/4rr2/Pp5Q/3N4/1p5K/1b6/8 w - -,31,766,20929,558041,14934017,409202894 -rnbq1knr/ppppp1bp/5pp1/3N4/6P1/4PP2/PPPP3P/R1BQKBNR b KQ -,20,660,14190,455024,10494459,332322796 -2r2b2/p1qb2k1/1p2p2r/1Pp1p2p/P1K2P1P/6B1/2PQP1B1/RNn3N1 w - -,37,1146,39873,1265706,42785488,1390846779 -1B6/B2n1k2/8/4nP2/2pK3P/R4p2/8/6r1 b - -,31,609,17529,370210,10137385,229717850 -r1b1kb1r/1p1p2qp/4Pnp1/p4p2/P1p2B2/5N2/4KPPP/R1Q2B1R b kq -,29,1141,34877,1357703,43199042,1679608140 -2b1q3/p1rpn1p1/P1p1R3/1pP2P1k/PB1P3p/4b2P/R3K3/1N2Q3 w - -,40,1046,41817,1090437,42069929,1110688523 -rn1q1bn1/p2p1kp1/bpp1p3/5p2/P1P5/5R2/RP1PPP2/1NBQKBN1 w - -,26,779,21676,652399,19033819,579239058 -rnbqkb1r/pp1ppp1p/5np1/2p5/P3P3/R7/1PPP1PPP/1NBQKBNR w Kkq -,37,919,32692,883810,31020731,897668046 -rn3bnr/p1p5/b2Qpkpp/1p1p1p2/PPPPP3/R2B4/3K1PPP/1NB3NR w - -,46,920,40594,855744,36800674,820936711 -8/4N3/4P3/P2k4/3n2P1/3b3p/8/K7 b - -,6,60,1326,13515,287484,3091289 -8/5k2/4r3/B4P2/8/7p/N2R4/5K2 w - -,25,477,11729,199164,4840593,80330662 -N7/6nr/5P1k/8/1pPb2P1/2RB4/Pp1q3B/RK6 w - -,26,817,17942,590102,13674345,471115279 -rnbqkbnr/1ppp1pp1/4p3/p6p/1P2P3/5P2/P1PPQKPP/RNB2BNR b kq -,32,866,28056,807478,26471915,800412443 -2b1kr2/1p1p1p1p/r1nq3b/pQP2PB1/P2p1N2/4pP2/1P1NK1BP/R3R3 b - -,27,1233,34936,1530476,44320188,1879554797 -1rbq1b2/2pkp3/n2p1n1p/3P1pp1/ppP3P1/PPB1P2P/3Q1P2/RN2KBNR w KQ -,30,772,24764,635387,21077449,557764143 -4n1n1/8/Bb6/1pkp1P1p/P3p3/1P5P/2p1R2R/3K2N1 w - -,5,91,1884,39801,881938,18952794 -k7/8/6B1/8/5n1b/8/8/6K1 b - -,18,190,3199,35738,616637,7160577 -5bb1/8/k1K5/8/7P/8/8/5R2 b - -,16,264,4348,69598,1189031,19114220 -1n2kbr1/1b6/3r4/1pB1p1pp/pPpP1n2/P4PPq/4P2R/RNK2BN1 b - -,52,1159,55381,1307118,59285711,1461178281 -2b2b1r/3pk2p/r3P1p1/pp2Bp2/P1q5/2p3PR/Q4PP1/R2KNB2 w - -,38,1335,43908,1483880,51464605,1725042339 -5Q2/5b2/p2bk2p/P5qP/5R2/8/5K2/5R2 w - -,34,948,27217,731427,21843935,580477397 -2k2q2/2P3b1/4b3/1p1pP3/1p2rr2/4B2B/4K1Pn/8 b - -,38,345,12216,156664,5957085,86655815 -1nb1qbn1/rp3k1r/p2p3p/N4ppP/P2N2P1/1P6/2PPPP2/1R1QKBR1 w - -,26,773,21005,628934,18027355,551377905 -6kr/1n6/8/5n2/2p5/2N5/7R/2K2B2 w - -,32,625,17016,357294,9113877,206146170 -r1b1kbr1/pp1ppppp/n1p4n/6Q1/3PPP2/2q5/P1PBK1PP/RN3BNR b q -,35,1093,36035,1146374,37344349,1212544280 -k4Nr1/r7/2P4n/1p1PK1Pp/1p5P/1P5q/8/6RR b - -,38,692,24541,467102,16104469,321131377 -1r3qr1/p4k2/1B2pnp1/2p2B1p/P1b1Pp1P/1P3P2/1R1P4/2BK1R2 w - -,24,838,20379,722598,18455539,665304463 -rk3b1r/1q3Np1/1p1p4/nb2p2p/1pPPPpn1/RNB2PPB/4K3/5R2 w - -,39,1574,57799,2274193,82802682,3225588905 -1r6/1k6/8/4BPpp/Pq5P/8/1R4KR/8 w - -,30,633,18307,512892,14278080,437394981 -r1bq1b1r/2pk2p1/np1p1p1n/1N2p2p/p2P3P/1PP1PQ2/P4PP1/1RB1KBNR b - -,28,1162,31403,1277431,36225433,1458273384 -b4rn1/p3k3/q2N3P/2P1ppn1/p1P2pPp/Q2PR3/4PP2/R2K1B2 b - -,38,1236,44338,1470793,53449688,1807775613 -1nb1qbnr/6pp/1p1kp3/r1p2p2/PQp3P1/B1N2P1P/3PPKB1/R5NR b - -,38,1366,45498,1594520,52075193,1810200283 -1n6/Bb3r1k/1P4p1/4pp2/2pp1PNP/4Pp2/1p6/4RR1K b - -,30,579,16828,356801,10538458,238250794 -8/2b5/2k1b3/6P1/2P5/1p1N4/4K1p1/N6R w - -,31,848,20518,540827,12143148,319126877 -1q3b2/5b1N/1k4p1/2ppQ3/2Bp3P/P1P5/2NK1PP1/2r3R1 w - -,52,1511,62498,1941375,76314627,2421451273 -5R2/1k6/3P1Nn1/1p6/1p1R3P/1P4K1/4q3/7r b - -,41,862,30641,687574,23484466,542221264 -b4rn1/p3k3/2qN3P/2P1pp2/p1P2pPp/Q2PRn2/4PP2/R1K2B2 w - -,29,994,30816,1077938,34929896,1228918886 -3r4/8/8/2k5/6p1/7r/5K2/8 w - -,5,185,656,22613,91572,3029785 -b6k/2K5/5R2/2P5/8/7p/8/8 b - -,11,226,2647,49726,612255,11194473 -2r1r3/8/8/1k1K4/6p1/8/8/8 w - -,2,56,134,4039,13548,401308 -r3k3/7p/4n3/1p3pp1/r5PP/5K1R/8/8 b - -,36,354,12521,162314,5616306,83099207 -r4bn1/2q1k1pr/B4n2/1pp1pp1P/p2PPPb1/P1P2Q2/1P5P/RNB1K1NR b KQ -,42,1449,60445,1999837,82648526,2699699386 -r4bn1/4k2q/5np1/1B3p1r/p1pQPP1P/P1P5/1P1Bb2R/RN2K3 w Q -,34,855,29114,783225,26628255,758922310 -5q2/p6k/PBn2P2/Bp1p2p1/3P3p/7P/5NR1/4Q1K1 b - -,30,1038,25471,911833,21354774,771678180 -8/Q7/5kp1/p2p1p2/R4P2/4B1P1/1p3bP1/5K2 b - -,11,282,3036,84328,1023977,29279812 -3b1r2/6k1/6p1/p3p2p/P3PP1P/7B/1Q1p1K1R/1RrN2N1 b - -,29,976,26665,978045,26594317,1015966662 -8/6N1/8/1p6/5k2/8/4K3/8 b - -,6,64,422,4550,29864,331785 -8/4k1B1/1p2p2r/1N3b2/pP3P1P/3R4/5QB1/1N4KR b - b3,17,955,15872,822730,14685119,731976081 -rnq1kbnr/N1p1pppp/pp2b3/3p4/2P2PP1/3P3P/PP2P3/R1BQKBNR b KQkq -,25,670,16904,486705,12785523,388456770 -4k3/4r2p/2b4P/3p4/p1p5/6p1/1bBBR2r/3K4 w - -,26,829,19779,634324,14856365,479281970 -k7/2q1n3/4K3/rp1P3R/1p4NP/1PR5/8/8 w - -,26,775,16424,488217,10418212,310025105 -1rb1k1nr/pp1p1ppp/n1p2q2/4p3/P3PP2/b7/1PPPB1PP/RNBQ1KNR w k -,29,991,29105,993496,30222799,1041301718 -1nqk3N/8/2rP4/R3KP1p/1P6/2Rp1P2/4B3/7q w - -,32,984,25502,842437,20554563,713101452 -8/r5k1/6B1/3b2bn/2np3r/2p5/3R4/4K3 b - -,55,1100,58283,1094378,55338090,1006899228 -4k2r/8/2n5/8/8/1K1p4/3N2N1/8 w - -,15,332,5052,113911,1739874,39669421 -2N2k2/4qr2/N2p4/Bp3n2/P1P3Pp/1P1PQP2/7P/2K1RB1R b - -,28,1283,37064,1651629,49012098,2160496556 -2rb4/2r1k3/8/1p1pB3/6P1/R4K1N/1p6/3N4 w - -,37,764,26054,645794,20670048,573258547 -5R2/6p1/3q3n/8/2K1bk2/8/8/8 b - -,10,139,5755,67005,2670339,32948515 -rn1qk1nr/p1pp1ppp/b7/1p2p3/4P1P1/b1P5/PP1PKP1P/R1BQ1BNR b kq -,30,704,21366,532394,16424294,428831037 -2b4Q/1r2n3/1N2k1p1/pP1p1p2/Pn1p1P1P/8/2RBP3/4KBNR b K -,17,619,10454,399109,7052020,274859647 -1r4R1/2k5/8/8/p4P1p/4K1b1/B7/6r1 b - -,32,657,19307,409376,12025506,256456164 -rn3k2/p6p/2p5/4Bp2/1b4PP/8/5P2/K1r3R1 w - -,3,83,2098,53349,1252366,32056549 -8/1n3k2/P1p5/4b1pR/1P6/6N1/2NB1r2/3K4 b - -,35,961,29537,831422,23896361,686496771 -4R3/2k5/1r6/8/p4P1p/4K1b1/B7/6r1 w - -,25,742,16496,486030,10698011,316384402 -k2B4/P7/2n4p/3p4/6K1/1q1p4/4N2n/3b4 w - -,6,191,2711,88040,1313733,43364608 -8/2k4p/7P/5q2/1r6/2R3b1/6K1/8 b - -,8,123,5249,70273,2841178,37291761 -8/3N1n1k/1N1p2Q1/6r1/P1pP3p/1P3P2/7P/2K2B1R b - -,3,93,1759,56133,1010630,32595012 -7r/4k1Bb/1p2p1q1/1N6/p4P1P/3R1B2/1P3Q2/1N3K1R b - -,26,1345,35522,1803008,50079914,2476547620 -1k1q4/5n1p/2b5/P2pn3/8/3pN1K1/3P4/6B1 b - -,37,565,20031,301797,10363976,153809902 -2bqkbnr/rpp1p1pp/n2p4/5p2/p1PP2P1/PP5P/4PP2/RNBQKBNR w KQk -,27,666,18637,493990,14425855,405138216 -rnbk1rq1/3p3p/2p5/p1b1Q3/PP4n1/2Np3n/1R1P3R/2B4K w - -,40,1648,55348,2335481,75682450,3231481658 -8/8/8/4n1N1/1k5b/4R3/K7/8 w - -,20,318,6444,103819,2140939,35043969 -2N2R1b/2r5/p5k1/p1p5/P7/N3K3/8/1n5N b - -,25,605,13850,331380,7682628,184183744 -5k2/2n4B/p2p4/P2P4/P1p4Q/b3K1B1/5N1R/8 b - -,13,383,4450,145583,1775551,61890500 -6rk/rp2B3/n7/2bpp3/P6N/1p4P1/6KP/RN6 b - -,31,649,17913,415486,11689292,291869472 -1r1rk2B/p1b5/P1P5/1RPP4/B7/N5P1/1P2K2P/2q5 b - -,35,755,25922,588536,19930319,467559824 -8/r2N2r1/4P3/P1pbb2P/3k4/4p3/1p1PR3/3K4 b - -,44,705,28954,485603,19176918,335703981 -rqb1k3/1p1N1N2/3P4/p4P2/4p1rp/P3Q2P/1P1BPK2/R4B1R w - -,43,784,29749,639299,24388590,587767868 -5b2/3n2kr/pp1p3p/PP4pP/2bP1Rp1/1R1BK3/2P4N/5Q2 w - -,41,801,31825,634880,25017291,515930805 -k2r1b1r/5p2/p2p1Q2/Ppp2pP1/3R4/R2K3b/1P5P/2B5 b - -,23,756,18156,619053,15498627,533488635 -3kr3/4r2p/p6P/npp1p3/2Pp2K1/P3b3/RP2N3/N4B1Q b - -,28,825,22622,656277,18551760,547935303 -1n3R2/3k4/5r1b/2pp2Pn/P6r/2pB4/8/1bK5 w - -,23,816,17024,591703,11991492,411741941 -4q1nr/pp3k1p/1N3p1b/2ppp1p1/1P4P1/B1P1PP1P/P1bPK1BR/R3Q1N1 b - -,35,1006,33882,971318,31644468,916318403 -8/3K3b/P7/8/8/1R6/8/4k3 b - -,12,252,3105,61913,784137,15227906 -6R1/p4k2/PN5B/2nr4/3p2K1/5p2/8/4b1n1 b - -,31,726,20091,446103,12093207,269825110 -2k3nr/p4p2/1pp1pP1b/1n5p/8/1BP2rPP/PP1N2K1/R1Bb2NR b - -,36,724,25633,572570,20513118,491675900 -rnb1kbr1/pp1ppppp/1qp4n/6Q1/3PP3/8/PPP2PPP/RNB1KBNR b KQq -,25,1116,30176,1275760,36652536,1497308724 -8/8/4R3/1k6/8/5n2/Kb6/8 w - -,17,342,5444,100412,1575092,27899919 -1n3k2/3q4/2rP4/3K1P1p/1P6/8/5R2/4b3 b - -,33,416,14606,195662,6949439,94934000 -r1bnk2r/p1p2ppp/7n/1p5q/Pb1pp1PP/BPN2P1R/Q1PPPK2/R4BN1 w q -,29,1306,36695,1580613,45452027,1904453228 -B7/5r2/p3N1k1/PP5p/5B2/3R4/1b1K4/8 w - -,42,991,36743,821448,29645265,648779509 -3r4/5k2/4N3/3q4/Pp2p2N/2RP4/6K1/1r6 w - -,27,1075,24878,983771,22462613,870483160 -3k1br1/rp2qp2/1n1p2pp/pPp1pP2/3P1Q1P/2N5/PBPNP3/3RKB1R w - -,41,1319,53494,1664908,68124388,2096822478 -8/r7/1k3pP1/p1pP4/PNP5/1Pq2p2/1B6/1R2K1R1 w - -,4,95,1862,45862,977029,24843716 -8/7k/3R3p/3p2pn/pp1P4/2Q2Kp1/2P5/6R1 b - -,11,359,3963,131438,1542427,51056863 -8/Q7/1B3k2/p2p1pp1/R4P2/6P1/1p4P1/4bK2 w - -,32,401,12819,175491,5262816,77389548 -2b2k1r/p6n/B2pp2b/P2rP1N1/6Pp/2R4P/2P2B2/1N1Q1KR1 w - -,47,900,37752,822524,34389397,813379288 -3b2n1/1k6/8/2pbbPp1/2R3PN/p3K2P/8/1B1N2R1 b - -,39,1065,37400,1024337,33993440,944801270 -Q7/5k2/p2Pn3/P3p3/P1pb4/2N2K2/8/4RB2 w - -,39,641,22113,376344,13017904,219230633 -rnkq3r/p7/b1p3pp/1p3p2/1P2P1P1/1P1K1pnP/P2PNR2/R1B2B2 w - -,4,145,2992,103018,2315877,78707989 -3n4/4Bk2/PPpr4/6p1/8/N7/1b2K3/5N2 w - -,19,535,10685,283609,5953899,155016627 -1B1R2n1/4k1b1/2r3p1/5p1r/pPN4P/2P2Kn1/8/2R5 b - -,34,1285,38772,1384200,41149080,1418335044 -r1b2b1Q/1p1ppk1p/7n/p4pp1/2P1PP2/6PN/1B1q3P/R3KB1R w KQ -,1,19,806,14487,587567,11211413 -2Nk4/r7/8/2K1P3/1Np1R2P/5p2/8/8 w - -,26,455,10591,166007,3872615,60016508 -kr6/r1Q5/p5P1/Pp3p2/1P1p4/R6b/3K3B/8 w - -,43,661,24875,441583,15409256,307563244 -8/8/k3p3/4P2p/K3P2P/5N2/2B5/8 w - -,13,43,611,3590,53806,267146 -8/8/2k5/5b2/8/8/5r2/4n2K w - -,1,33,65,1905,4927,125932 -2rkn3/5R1B/Pp6/2p4P/1NP1p1p1/1R6/8/4K3 w - -,38,441,15770,208224,7208173,104442635 -1k6/5n2/1p6/5rp1/K5P1/1Rpp3N/7P/7b w - -,14,381,5607,152130,2437325,66425102 -rnbqkbnr/pp1pppp1/2p5/6Pp/8/3P4/PPP1PP1P/RNBQKBNR w KQkq -,26,545,14363,341701,9400789,245723070 -3B1k2/rp6/P6r/R2pp1K1/8/1n1N2P1/1p5P/1N4b1 b - -,36,961,32290,855487,28282354,752664255 -2k5/K3R3/2N5/8/7P/5p2/3r4/2b5 b - -,17,349,6490,132545,2488534,49327093 -4k3/7B/1p3R1n/1r4p1/K3b3/2pp2P1/7P/1R4N1 w - -,34,862,25831,634668,18154957,448972335 -r3kb1r/1p1b4/1qnpp2p/2pn1pp1/2Q1PN1P/1NPP1P2/PP4P1/R1BB1K1R w - -,39,1770,69135,2979618,118000269,4928117816 -r7/1ppP3r/pk6/1P2npbp/1K3p1P/N4PP1/P7/4nbN1 b - -,43,592,22804,364639,13685924,241295291 -3BNR2/7k/7p/1p1pP2P/Pn1p4/1R6/b2K1PP1/8 b - -,8,301,3017,106240,1118797,37283332 -n7/3k4/8/1P1P2n1/3P3P/2p1K2R/2Q5/1N6 b - -,14,442,6045,178335,2418493,70778262 -b6n/6b1/P1pBkP2/8/p1Pp2P1/6p1/2NRB3/1N4K1 w - -,33,435,13770,199179,6240328,97267876 -5Bk1/8/b7/8/7b/3p2p1/K5P1/8 w - -,12,153,1758,27616,324700,5700893 -1Q6/3P4/p7/P3pk2/n1p5/2N2K2/8/2bR1B2 w - -,45,630,26050,370785,15143320,218123401 -r1b1kb2/p2p3r/4N2p/1p1ppppP/1n2q3/P3P3/1PPB1PP1/RQ2KBNR w Qq -,36,1187,39412,1330569,44063374,1506407779 -3N2r1/2kN4/2nb4/8/3p4/8/8/2K2n2 w - -,14,459,6308,194109,2637202,79745057 -8/3NP1r1/2b5/r3b2P/2pk4/3Pp3/3RK3/1q6 b - -,59,857,45340,732001,36909396,661237121 -rqbk2r1/pp1p1p2/1N1P4/2p2PNp/4p1Pn/Q6P/PP2PK2/R3BB1R b - -,20,775,16210,622373,14049395,537793284 -rnbqkbnr/pppppp1p/8/6p1/2P5/8/PP1PPPPP/RNBQKBNR b KQkq -,21,462,10556,259039,6427261,171946254 -1nbqkb1r/2pppppp/rp5n/p7/3PP3/5N2/PPPN1PPP/1RBQKB1R b Kk -,20,540,12282,362660,9091190,285531964 -3nrb1r/ppp1k2p/3pqp1n/2P1p3/P7/BP4Pb/3PPPBP/RNQ1K2R w K -,32,959,30449,962706,30904368,1010996135 -7r/1B2k1B1/1p2b3/1N2p3/1P2QP1P/p1R5/8/1N4KR w - -,55,1426,77003,1713145,90963271,1894651921 -3k2b1/6P1/8/1P3B2/8/p7/4KB2/4R3 b - -,11,355,3938,130386,1525058,50949775 -8/2R5/8/k7/N5PP/2K5/8/5b2 w - -,21,192,4350,41007,924804,9388613 -8/8/1k1Np3/4P2p/K3P2P/8/6B1/8 b - -,5,75,293,4335,19978,298767 -8/3K4/6pP/5nk1/2r5/2p2p2/8/8 w - -,4,107,569,14150,100240,2362837 -8/4r2k/3Np3/p1N2p2/P4Pp1/8/8/4K3 w - -,20,271,4947,71580,1259241,18881893 -1N4B1/8/P5P1/3r1R1k/7P/3p4/K7/2b1N3 b - -,6,151,2707,68908,1350094,35824284 -8/6Q1/p2bk2p/P7/5R2/8/4b3/4R1K1 w - -,46,493,19006,245109,9422857,134067345 -5b1r/6k1/pp1p2np/1P2nqpP/P1bP2p1/4KP2/2P2R1N/1RQ2B2 w - -,27,1056,27919,1067535,29437503,1112107850 -8/3k1p2/6r1/p1Brp1Rp/1b6/p1PN3b/3K1P1P/1R5B w - -,38,1277,46396,1500655,54409364,1735976483 -r4b2/p1qb2k1/1p1pp2r/1Pp1P2p/P1K2P1P/3Q2B1/2P1P1B1/RNn3N1 b - -,29,1075,31302,1078491,32589912,1084370023 -1N6/8/P1R3P1/3Br2k/7P/3p4/1K4N1/2b5 w - -,7,127,3420,61898,1720202,32169538 -b4rnr/3p4/2n3pb/p1p3k1/2p2N2/P4P1B/4P2P/3K3R w - -,22,550,12413,320698,7256619,197656688 -r1bqkbnr/p2ppppp/2p5/1p2n3/1PN1P3/7P/P1PP1PP1/R1BQKBNR b KQkq -,26,723,19480,568199,16276143,494689045 -1k6/4B2p/3pp3/1Q3pRP/2pPn3/4b3/8/KR5B b - -,4,176,2651,113840,1723361,74736536 -rnbqkb1r/p1pp1ppp/1p3n2/4p3/P5P1/7B/1PPPPP1P/RNBQK1NR w KQkq -,20,579,13064,398902,9849229,311512474 -rk3b1N/q5p1/1p1p3n/1b2p2p/1pnPPp2/2B2PPB/R2NK3/3R4 b - -,35,1152,41448,1353738,49829294,1622754275 -rnb2b1r/pp2p1kp/6pn/2pN1p2/Pq3B1P/3P4/2P1PPP1/R2QKBNR w KQ -,5,155,5421,163040,5725784,175752253 -8/3Q4/8/2k5/4Q3/3K4/8/5B2 b - -,1,54,143,7321,15058,759669 -rnbqkbnr/ppp1p1pp/8/3p1p2/N4PP1/P2P3P/1PP1PK2/R1BQ1BNR b kq -,25,674,18016,502451,14293915,413057870 -5k2/6p1/8/4K3/b3pP1R/6qn/7P/1N3q2 b - -,49,668,29127,390158,16547950,229532138 -8/p2n3k/P4P2/qp1p2p1/3P3p/2B4P/3Q2R1/2N3K1 w - -,30,604,19475,399305,13004615,272627639 -4k3/8/8/1Pn5/8/6B1/5K2/1b6 w - -,15,295,4629,87871,1329037,25078540 -6n1/6r1/r2k1p1p/p6P/P5P1/3P1P2/2NB1bBK/6R1 w - -,30,913,24522,705271,18507525,518292350 -r1n1k1r1/1pb2p2/5P2/pPPp2p1/5p1R/P1N1N3/2P1P3/B1R1KB2 w - -,32,809,26012,635878,20581564,495643496 -8/8/4Q2P/1kB5/3P4/2R3b1/8/1K6 w - -,47,440,19527,177783,7661474,69290147 -4N3/5kB1/4R3/1B3bP1/1P1Rp3/p7/8/6K1 w - -,41,358,14013,136297,5221359,55977437 -8/5k2/3r4/5PR1/1B6/7p/N7/5K2 w - -,22,383,8976,133520,3173095,49299874 -r1b2kr1/p1p3pp/n2p1b2/PN2P3/4P3/2P3P1/1P3P2/2R2KNq w - -,21,741,14527,526835,10691219,396171048 -1rb2rk1/np2ppb1/1p1qPnp1/2p4p/2Pp3P/PN1PBPP1/1P2N3/R2K1B1R w - -,34,992,32236,983237,31063998,988167155 -r1b1kb1r/2Bpq2p/1p2Pnp1/p4p2/P1p5/5N2/4KPPP/R1Q2B1R w kq -,39,1163,44177,1403010,53152585,1761646448 -8/r3kb2/np5N/4PP2/P2P2P1/1b3RBK/2B5/8 b - -,26,705,17204,470287,11776493,326584812 -8/p7/P3k3/K2p4/3Pq2p/2N5/1B6/8 w - -,14,301,3754,87276,1079854,24930771 -6k1/8/8/6b1/1bK5/8/8/8 w - -,6,129,760,15655,86449,1753862 -8/4rk2/8/5P2/1B6/7p/N5R1/5K2 b - -,16,384,5757,136292,2164506,51230924 -8/k7/4P3/Q7/8/5B2/2K2bP1/8 b - -,1,41,364,13307,122353,4232679 -3q1b2/3b4/Bpk2ppr/2ppQ2N/3p3P/P1P5/2NK1PP1/1Rr3R1 b - -,32,1582,43927,2013647,58624017,2541942379 -r1bqkb1r/pppppp1p/2n2np1/8/4P3/2P5/PP1PKPPP/RNBQ1BNR w kq -,25,624,16142,432079,11777431,332748109 -2b1k3/r1np4/1P1P3n/4Npp1/pP6/P2KB1P1/7r/bN3B1R w - -,29,933,26642,833139,24298532,752087883 -5B1r/5b1k/1p4RP/1Pnp1p2/6N1/1p1p4/6BK/8 w - -,26,452,11785,217628,5780151,113812683 -3n4/5kb1/P1p5/1P4p1/1B6/N7/5r2/3K1N2 w - -,20,615,12065,357128,7205845,207604384 -8/6P1/p2b3p/P3k2P/5R2/1b1p2P1/8/3RK3 b - -,19,460,8206,198643,3519056,87580515 -8/8/2Np1P2/1bq5/5kn1/6R1/K7/8 w - -,23,785,14378,470114,8385707,272365356 -3Q4/3b2k1/1N4p1/1P1pnp2/Pp3P1P/3P4/4R1B1/4K2N w - -,40,590,22136,332911,12957459,193324484 -7r/4k3/1R4B1/2K5/5P1p/p5b1/8/8 b - -,19,462,8415,205841,3981623,94823553 -rnbqkb1r/ppppp2p/5ppn/8/1P4P1/7P/P1PPPP2/RNBQKBNR w KQkq -,20,419,9488,218491,5456966,135934212 -1r6/p2pkNr1/b2b3p/1n1pp1pP/2BB1P2/P5R1/Q1P3P1/1R2K1N1 w - -,52,1729,83846,2731013,127553042,4093036428 -q1r3nr/4p1k1/8/2p1P3/4BPpP/3bb1P1/R5K1/6NR b - -,42,996,42817,1052959,45801761,1165594223 -k3r3/8/1P6/r7/1K4p1/7n/8/8 b - -,33,167,4261,25673,691794,4115471 -3n4/N3Bk2/PPp2b2/6pN/8/7r/8/6K1 w - -,18,485,8668,228750,4326269,113181561 -rn3bnr/p7/b2ppk1p/5pp1/pP1PP3/R2p4/4NPPP/1NK1B2R b - -,22,609,14291,399581,9997865,280882741 -8/8/8/3kP2P/8/4K3/3N4/8 b - -,4,54,311,4449,27989,401170 -1n2k3/N1bb4/pp1n1r1p/1B1pp3/3pPp1q/PPP2K1P/3B4/1R4NR b - -,33,763,26952,610727,22406608,515119666 -rnbq1bn1/pp1ppkp1/2p5/5p2/P1P5/7R/1P1PPP2/RNBQKBN1 w Q -,32,728,22753,546322,17404060,441961845 -2b2b1r/3pk2p/rp2P1p1/p3Bp2/P4q2/2p3PR/Q3KPP1/R3NB2 b - -,32,860,24940,756153,22414551,727939876 -8/8/Q5RP/k1B5/3P4/8/8/bK6 b - -,0,0,0,0,0,0 -1r3kr1/p1p3pp/n3bb2/P3PN2/4P3/2P3P1/1P3P1q/1R2K1N1 b - -,43,968,41615,915715,38781964,844846990 -8/8/8/1K3k1r/3b3p/p7/8/4R3 b - -,24,425,9215,154284,3482581,56634127 -3k4/r5b1/1qP1b2r/1p1pp3/Bp1P2n1/8/4N1PR/5KB1 b - -,45,782,33700,678556,29075113,635584074 -rnbqkb1r/p1p1p1pp/1p1p1p1n/8/5P2/N3P3/PPPP2PP/R1BQKBNR b KQkq -,29,860,23065,691202,18699344,572764113 -5b2/8/5r2/p3K3/P5N1/8/3k4/8 w - -,9,214,1969,42312,389751,8409607 -r3kbnr/p7/1p1B1q2/3b1p1P/PpPp4/2Q4N/3PPP1P/RN2KB1R b KQkq -,44,1613,68653,2455013,103210254,3674650964 -rnb2k1r/1p1p1pp1/2p2n1p/1pb1pPP1/P7/1qB1P3/2PP3P/RN2KBNR b KQ -,45,1334,57679,1681259,70241389,2044282765 -1r2bb1r/1Bn3k1/p2p2qp/P1p2p1R/3P1p2/P1K3p1/3B4/RQ4N1 w - -,46,1515,61098,2091330,82568156,2892352878 -3kr3/3r3p/p6P/npp1p3/1PPp2K1/P6Q/2R1N3/N4Bb1 b - -,27,843,23082,747156,20845869,692757836 -1N6/4k3/2K5/1p2PN2/R6P/2P2p2/3r4/8 b - -,5,148,2703,72687,1165540,30467229 -B1k5/n6r/p4r2/PP6/1P1B3P/7K/4N3/8 b - -,30,843,22876,617224,16330280,428027342 -8/6b1/1k4P1/1bR5/8/1N6/4N3/2K1b3 b - -,27,594,14722,339783,8332975,194316207 -1k6/8/B3p3/4P2p/1K2P2P/8/8/5N2 w - -,18,63,1092,4489,76298,350216 -1n1q1r1k/1b1pP2p/rp4p1/P5BP/2Qp1p2/5R2/P3PPP1/R2K1BN1 b - -,27,1488,39746,2032970,57834957,2816924949 -7r/8/2n2npb/pRpp3k/P1p1b2r/2K2P2/6BP/8 w - -,16,622,9794,362688,5752613,207357450 -k4b1r/5Q2/p2p4/Ppp2pP1/3R4/R2K3b/1P2r2P/2B5 w - -,41,1067,36294,941519,30122674,793964338 -5N2/b4B2/P5Pk/8/3p4/7P/2R1p3/2K1N3 b - -,7,195,1860,50751,564501,15431261 -8/3k3P/6PB/3BP3/1K6/8/8/1b6 b - -,11,364,4020,119673,1369708,38385877 -8/4n3/4P1P1/P2N4/8/2Kb1k1p/8/8 b - -,23,330,6866,97759,1963774,27800231 -rnb2k2/bp1p1p1P/2p2P1p/1p2p3/P7/1qB1P3/2PP3P/RN2KBNR b KQ -,25,746,18235,534014,13642878,400025565 -r3kN2/2q2N2/3P4/pp3b2/4p1rp/P3Q2P/1P1BPKB1/R1R5 w - -,53,1853,88125,2923058,133967790,4379885577 -r1q1k2r/p1p2pbp/b2p3n/np1Qp1B1/3PP3/P5P1/1PP2P1P/RN1K1BNR w kq -,48,1291,57318,1594947,68002120,1976840584 -3nB3/k5r1/r7/p3p3/3b2p1/3K2B1/8/3N4 b - -,34,722,23773,495991,16101243,335393939 -4k3/3r2b1/1q2b2r/1pPpp3/Bp4np/3P4/4N1P1/5KBR w - -,21,846,17253,697548,14989357,611729264 -1r1k1b1Q/pb2p3/np6/P1pP1n2/1P1Pp3/B4N1p/5PPR/R1N3K1 b - -,29,973,27173,943770,26105312,939090966 -8/k2B4/4p3/4P2p/4P2P/8/7N/K7 b - -,5,60,289,3998,19738,289863 -3R4/8/3p1P1k/N2r4/3K2n1/8/7p/3b3n w - -,4,90,1265,30258,484867,12271951 -k4N1r/8/4K2n/1pPP2Pp/1p5P/rP3q2/8/6RR w - -,22,821,14957,546558,10632810,386989910 -8/k2rN3/5r2/1P6/K5p1/8/8/6n1 w - -,11,270,2907,79975,845937,23835832 -2k5/5n2/8/8/2K5/3r4/8/8 b - -,25,110,2461,13954,310830,1595055 -rnb2br1/p1ppkp1p/1p2q3/1N4p1/2P2B2/1P1PP1Pn/P6P/RQ2K1NR w KQ -,28,1011,29488,1069129,32702855,1196810099 -b7/k7/4N2P/P7/5b2/3r4/4pK2/8 b - -,39,449,15877,166012,5512163,57084207 -2k5/1p2B1bp/3pp2n/3Q1p1P/r1pP4/7R/2K1P3/6RB b - -,25,1216,28420,1305063,30836056,1364892759 -1k4N1/8/6P1/2b1q2n/8/8/8/6NK w - -,8,329,3089,118429,1231357,44988126 -1B3k2/2r5/1b6/1p1pp1N1/6K1/R5P1/1p4N1/7r w - -,26,1050,25959,997991,24921881,918909597 -3r4/4N3/N3k3/1pK1P3/R6P/2P2p2/8/8 b - -,21,473,7966,174743,2804413,62344441 -r4b1r/p3pkpp/n2P1nb1/2p5/3Q1P1P/P2P4/1N2P2R/R1B1KBN1 b - -,29,1034,27397,999607,26772387,997457947 -5k2/2n5/8/rb3pP1/1pRp3p/1P4nP/8/1K6 w - -,12,374,4955,149827,2028005,59793734 -1r5B/p1p3p1/2r1P1k1/P5P1/n1Rb4/1P1N2N1/3K4/8 b - -,35,1080,33407,955027,28808431,786400344 -4n3/6b1/r6p/P1k1p1p1/4B1P1/2PPP2P/R3b2N/B3K3 w - -,25,557,13980,314612,7936760,183398372 -8/4R3/6R1/2p5/2P5/7K/3N4/q2k4 w - -,38,685,21067,405132,11285404,217619828 -1r6/1B2k2b/n6p/4B3/6K1/3p4/8/R2r4 w - -,35,1062,32163,1004452,29618686,938443308 -1K6/4Nk2/p7/p7/P1N5/8/8/2r5 w - -,19,309,4805,81777,1240531,21028626 -8/2N1r3/7k/8/Qp5K/3B3p/8/8 w - -,35,512,16116,236373,7385137,110184413 -7r/8/1k6/8/2K1b1p1/8/8/1r6 w - -,2,91,376,16108,69771,2862154 -3r1k2/8/1p2B2N/1P5K/P7/6R1/8/b3b3 b - -,26,827,20350,565484,14098055,370091724 -6k1/7R/8/2B2b2/3p3b/6p1/K5P1/8 b - -,17,344,5354,109291,1781999,36616537 -1r6/P1pr2Pn/4k2p/P2p3P/3Pp3/1P2K2R/1BB2R2/3b4 b - -,29,1071,27411,989857,24910926,893810186 -1B1N4/1r5k/1bB5/Pp1R3p/8/8/2K5/8 w - -,36,738,25979,529242,18418391,375624341 -r4bn1/4k1pr/B1q2n2/1p3p1P/p1ppPPb1/P1P4Q/1P2N2P/RNB1K2R b KQ -,43,1308,56010,1684462,71290393,2161779655 -rnbqkbnr/pppppp1p/8/3P2p1/8/8/PPP1PPPP/RNBQKBNR b KQkq -,20,564,12310,369350,8720822,276247626 -7k/Pp6/4pnp1/5p1p/5R1P/2r5/3bK1b1/8 b - -,39,606,21719,336528,11843048,189708368 -bb2N2r/8/3n4/p6k/2P1BP1p/3KP3/Pq6/1Rr5 w - -,21,871,16136,672533,13748868,569905573 -2k5/K7/8/4r3/1N5P/3R1p2/8/2b5 w - -,21,435,8127,161052,2998837,60628525 -3K4/5R2/P7/7b/8/8/8/5k2 b - -,6,103,1047,16980,201116,3435999 -b6r/8/3N4/p4B1k/2P1PP1p/3K4/P7/1Rr3q1 b - -,40,893,33414,760163,28158351,647547279 -4rk2/p1b5/PRP5/2P4r/2N5/2B2KP1/1P5P/2qB4 b - -,44,1222,50438,1347835,54494084,1425835541 -Br4r1/6B1/p6p/1N5k/PPp1P3/3p4/8/2RK2b1 b - -,29,752,22904,576614,17788816,446627007 -r3kbn1/p1r5/1PB2p1B/2p1p2P/P1P5/2R2N2/8/4K1NR b - -,5,188,3809,142138,3013776,111918224 -3rk1Br/2p5/4pbp1/ppP1P1Bp/P7/1PNRQP1P/4K1P1/6R1 w - -,46,917,41939,861677,39011957,795997545 -2b4B/bN1k3r/7p/2P4P/4p3/P7/R2P3N/n3K3 w - -,24,370,8685,167383,4012805,85539458 -6b1/k1K5/6R1/8/7P/b7/8/8 w - -,19,270,4548,73187,1195155,20337649 -1r1q1rk1/np1bpp2/1p3npb/2p4p/P1PB1N1P/3P1PP1/RP1NB3/3K3R w - -,32,1084,34300,1150681,36466996,1237981790 -2kNnb2/8/3p4/3P1bp1/prP2PPp/4K2P/p1NR4/6RB w - -,34,1070,33425,1055159,32170746,1009082628 -4N3/8/1b2N3/p3rp1k/P4P2/8/8/K7 b - -,20,258,4341,55232,1011238,13269198 -2b5/6r1/rp4N1/p1k1bp2/PpPpP3/RQ1B1q1P/3P4/1N2K1R1 b - -,41,894,35891,836880,33193321,824948575 -r1bqkb1r/pppp1p1p/2n1p2n/6p1/3P4/6P1/PPPQPP1P/RNB1KBNR b KQkq -,30,861,26388,811180,25294953,820683691 -Nnb3nr/r1ppk3/5pp1/pPb3p1/3p1P2/1Q2B2P/P2qP3/2R1KBNR w K -,3,100,3759,123251,4410599,147839983 -8/r7/4N3/p1b2P2/P7/8/3K3k/8 b - -,24,356,8117,107330,2417419,29333284 -3k4/8/1n3n2/1P1P4/3P3P/2p3Rr/5K1B/1N4Q1 b - -,23,569,11875,328540,6913258,205647479 -8/4n3/4P1P1/P2N4/4k3/K2b3p/8/8 w - -,15,257,3431,66613,873877,17136665 -rnbqkbnr/pp1pp2p/2p5/3B1pp1/4P3/5P1P/PPPPN1P1/RNBQK2R w KQ -,33,701,22671,532304,17059394,435272725 -q7/2k1r3/p3pnp1/7p/P1pPP2P/4rP2/R4KB1/2B1R3 b - -,44,1106,44727,1114903,42808935,1077631850 -r1b1k1r1/p1p1bppp/n2p4/1N2p1B1/P2PP3/8/1PP2PPQ/R4KNq w q -,41,1242,46297,1463119,53289845,1743853465 -r1b1k1n1/5pr1/n1p5/1pbPp1q1/Pp5P/N1PPBP1B/8/2RQK2R w K -,42,1890,71770,3233859,122457926,5514224647 -b3n1r1/1k1B4/8/3p2p1/P2P3p/8/1Kn4Q/8 w - -,30,510,15358,290132,8554988,173252524 -1k6/5n2/1p2r3/6p1/1K4P1/1Rpp3N/7P/7b b - -,32,398,12318,187541,5576476,93478453 -8/p6k/P7/1p1p2Q1/3P2np/7P/4N3/B2q1RK1 w - -,28,418,12005,211248,6263212,119173013 -Bnbqk2r/2ppppb1/pp4p1/7p/P5n1/2P1P3/1P1P1PPP/RNBQ1KNR b k -,32,934,28736,861813,26216062,807853209 -6n1/b3k3/8/1PP3P1/5r1N/p4R2/7r/6K1 w - -,17,472,7642,208161,3437633,94586812 -r1bbk1r1/p1p3pp/n2p1B2/1N2P3/P3P3/2P3P1/1P3P1Q/2R2KNq b q -,31,918,28050,845727,27221324,833703869 -rb4b1/2r5/1p6/p1P1P3/Pp2p3/N2k3P/3P3R/3K4 b - -,26,346,9009,131423,3408701,54063860 -4N3/5k2/4R3/1B2B1P1/1P2b2R/p7/4p3/5K2 w - -,5,93,4152,57092,2441627,32988610 -bk1q4/3n3p/2P4n/P2p4/2N5/3p3K/3P4/6B1 b - -,27,482,11808,204871,5252093,90191512 -1k3B1r/7p/1r2p2P/p3pBp1/1n3P1P/P1Np3K/8/R1B1R3 w - -,42,1009,39614,993324,38368028,995098742 -2k3nr/p4p2/1pp1pP1b/1n5p/8/1BPr2PP/PP1N1K1R/R1Bb2N1 w - -,24,900,21243,796155,19760447,739683984 -8/6Bp/7P/8/1N3Pk1/BR1p2pr/6K1/3R4 b - -,10,296,3178,98239,1224067,40072698 -6q1/3Nk3/3pB2n/3P1Pb1/4pr1R/8/7p/2n1K3 b - -,34,505,16720,271798,9123663,154379592 -b2bB3/2r5/7k/8/8/2p5/1n2K3/3r3n b - -,42,307,13027,109267,4671379,41793093 -1n3B1r/5b1k/1p3pRP/1P1p1N2/1p6/3p1B2/7K/8 b - -,13,415,6058,180761,3005461,86582335 -3rk3/1q4b1/4b2r/1pPpp3/Bp4np/3PB3/4N1P1/5K1R b - -,42,1041,42598,1030120,42505078,1031823868 -k4b2/8/8/2p3NP/4bK2/P1P1p1P1/1rN2PR1/8 w - -,23,657,14296,402290,8606392,239957693 -8/8/1K1k4/7P/4r3/8/5pN1/6b1 w - -,10,248,2192,53041,480584,12008276 -1rb1k1r1/p1p1p1bp/1N2P3/3p2p1/QP1B1NP1/P1nP1Pn1/7P/3R2KR b - -,6,224,7699,272720,9074843,327359686 -4k1nr/2p2p2/p3r1pp/1P1p3q/Pn1P1P1P/1P2P3/4R3/RBBNKb2 w - -,29,1065,26920,992157,24828455,919598899 -6k1/7b/1R6/4b3/3p4/B5p1/1K4P1/8 w - -,21,323,6359,105240,2132838,36768208 -8/1k5b/8/p7/8/7K/4r3/8 b - -,30,99,2839,15282,429905,2045880 -6br/5k2/R1B4p/1rP5/3p1nKB/1P2p2R/8/8 w - -,35,747,26205,568291,19617664,453329239 -r2qkb1r/p2bp2p/npp2p2/3p1np1/2B2P2/2PPP1PP/PPN5/R1BQK1NR b KQkq -,32,964,30688,964857,31650028,1022136798 -8/6rk/5P2/2P5/qp2R1P1/4K3/7b/1B6 b - -,36,644,15883,299406,7774759,152476175 -1r4nr/2p1p3/n6k/bpP1Pbq1/4B1pP/N5P1/P3pPK1/RB4NR b - -,42,1003,41323,1024405,42787168,1114695434 -1k4r1/4n2P/p7/P1p3RB/1P6/1P5P/1N3Kb1/1rB3r1 b - -,37,1276,43884,1439723,50224390,1608859404 -8/7p/8/3N4/1R3P1k/B2R2p1/6K1/B6r b - -,13,400,4997,162878,2058003,70472461 -8/3k4/n4P1p/rp4p1/7P/8/2r2RK1/8 w - -,13,357,5169,139712,2160150,58437524 -r3k1nr/p4p2/1pp1pP1b/1n5p/2B3b1/2P2N1P/PP3KPR/R1B3N1 w kq -,32,941,29398,893505,28225270,876330869 -8/8/1Pk5/5p1p/7r/b2P4/4N3/B4K2 w - -,19,438,7740,175393,3137500,70571477 -2B1k3/7N/Q4b2/PN1p2P1/R6p/2r1p2P/4K2R/8 w - -,40,684,27069,465629,18742901,319519887 -2rk2nr/pbp2p1p/4p1pb/1p1pq3/2B1P1PP/N4P2/P2P1K2/RQB4R w - -,32,1311,39216,1529770,47319600,1798563326 -r1b5/ppp1n2r/1k1p1p1b/5Qpp/4PpnP/NP3PPR/Pq2K1B1/4R1N1 w - -,4,160,4441,167517,4665407,182319417 -1rkN1b2/2n5/3p1q2/3P1bp1/pPP1PPPp/7P/p1N2K2/3R2RB b - -,41,1382,54678,1746961,67741175,2093738115 -2n1k3/1Q1bp3/N3P1r1/p6P/4K3/2r2P1p/8/3R3n b - -,34,1050,31186,934810,27366351,811168589 -1b6/4P1r1/2b5/r3N2P/2Pk4/8/3Rp3/4K3 b - -,5,120,4152,93562,3176622,72243882 -8/1k5p/7P/5q2/1r6/8/6K1/2R1b3 w - -,14,590,7190,287906,3637290,142518856 -2k3nr/p4p2/1pp1pP1b/1n5p/2B1N3/2P2rPP/PPb3KR/R1B3N1 b - -,40,1093,39621,1120063,40293595,1175505236 -rnbqkbnr/ppppppp1/8/7p/8/3PB3/PPP1PPPP/RN1QKBNR b KQkq -,21,625,14654,430274,11087675,326887682 -1n2k2r/rb1p2bp/1PQPp1Pn/5p2/pP2P3/5Nq1/P3KP2/RNB2B1R b k -,43,1898,76592,3181227,125757170,5073769472 -1r5k/5b2/1p5P/1Pnp2B1/5Rp1/3p2K1/2b3B1/8 b - -,27,709,18111,489433,12495614,335558020 -5Nq1/4k3/3pB3/3P1Pb1/4prnR/8/8/2n1K2n w - -,18,476,8077,236547,4045992,125900976 -q7/8/7B/R3P1P1/3K1k2/Pp6/8/8 w - -,16,323,4610,97778,1472169,32246813 -r1bqkbr1/p2p2p1/1p2pn2/2n4p/P1pP4/N6P/RPP1P1P1/2BQKBNR b Kq -,30,739,23545,630845,20805907,592344222 -6n1/2p2r1r/P2k2Pp/P2p4/1n1Pp1bP/1P2K3/BB6/R4qR1 b - -,52,849,38690,706272,29381336,583537005 -7R/k3n3/2qPK2N/1p5R/1p5P/1P6/8/r7 w - -,22,807,16892,576087,12594347,411246029 -rnbqk1nr/1ppp1p2/p3p2p/6Q1/1b6/2N1P2N/PPPP1PPP/R1BK1B1R b kq -,28,1201,32490,1333820,37363748,1492145090 -r1bqkbnr/pppppppp/2n5/8/4PP2/8/PPPP2PP/RNBQKBNR b KQkq -,22,658,15732,478442,12309804,384036001 -2N2knr/3n3p/p7/p1pP4/P1rb2p1/3RPP2/1q3N1P/2B1KBR1 w - -,32,1255,33797,1275937,35971234,1332143291 -8/3N2r1/2b1P3/r3b2P/2pk4/3Pp3/1p1R4/3K4 w - -,18,832,13987,621807,10890239,468591056 -2k3r1/6n1/1n6/1K6/8/8/8/8 b - -,18,102,2123,9690,221409,1091423 -2b1kbnB/rppqp3/3p3p/3P1pp1/pnP3P1/PP2P2P/4QP2/RN2KBNR b KQ -,27,729,20665,613681,18161673,570898339 -1k6/1bN5/8/8/3b4/r1B5/3Kp3/8 w - -,16,548,7834,260578,3791294,122168594 -6n1/6r1/r4p1p/B1k4P/P5P1/3P1P2/2N2bBK/6R1 b - -,28,723,18892,477975,12495040,317506026 -1Qn2k2/4p3/N3b3/p4P1P/8/1R2K2p/8/1r4rn b - -,33,996,33669,1039076,35826797,1118713782 -3Q1b2/k7/8/2p3NP/2bp4/P1P2KP1/2N2P1R/1r6 b - -,33,1140,28032,989698,23480539,829213301 -8/7Q/7n/8/7k/K7/8/8 b - -,5,105,756,19104,147773,3838511 -8/4k3/8/1K6/4q3/6B1/8/6Q1 w - -,28,730,16513,387362,9348042,201384840 -5k2/2b5/1p5N/PP6/2B2bK1/8/5R2/8 w - -,29,329,9348,147386,4146442,70361562 -5N2/4k3/2Bp1b2/3q1n2/4p1nR/8/8/4K3 w - -,21,738,14327,510272,10027825,356832416 -4k1r1/8/1Bb1n3/1pnr2p1/p1p2P1p/b3pNP1/5N2/RK3BR1 b - -,43,1389,60542,1961773,85468488,2797051852 -8/8/1r3P1k/2p2P2/1rR4P/1b4Pp/8/R6K b - -,19,476,11479,263895,7096491,161277192 -3r4/p1p3p1/n3P1kp/Pr4Pq/2bbP3/1P3PN1/2K1N3/2R5 b - -,51,1141,54590,1261196,59145434,1378781526 -k4N2/8/2P1K2n/rp1P3p/1p5P/1P6/4R3/2R3q1 w - -,31,926,23557,674154,16354802,466836766 -1b6/8/6B1/k3p2N/8/2P5/K6p/8 w - -,18,209,3734,54477,954283,16003896 -1B6/5R2/2r1kbp1/5pnr/pP5P/2P5/2N1nK2/2R5 b - -,34,1091,34735,1080890,35000364,1069575251 -rqb1k1r1/pp1p1p2/1N1P4/2p2PN1/4p1Pp/P1Q4P/1P1BPKn1/R4B1R b - -,18,773,14846,605029,12744958,502497571 -7k/5b2/7r/pP3B2/P3PpP1/1R3R2/3nK3/2b5 w - -,27,833,20639,591447,14508139,408859512 -rn4k1/p6p/2p5/5p2/3b2PP/6B1/K7/1R6 b - -,25,665,15032,377332,8424587,205467762 -4k3/3n4/3R3p/p2p1NpP/1p1P2p1/8/2P2K1Q/R7 w - -,43,481,19548,201100,7920512,84505246 -2b5/8/5r1k/P2p1pn1/1p3PPp/1P2R2P/3n4/2K5 b - -,29,478,12683,201350,5264728,82330892 -4k3/2Qb4/8/Rp1KP3/7P/1pPN1p2/3N4/8 w - -,39,413,14792,158715,5990246,68816815 -rnbq1bnr/2pk2pp/1p1p1p2/p3p3/7P/N1P1P3/PP1P1PP1/R1BQKBNR w Q -,34,814,27380,697557,23552398,628659907 -k7/3N4/2P1K2n/rp1P3p/1p5P/1P6/2R1R3/3q4 b - -,24,586,14923,362819,9598563,233530974 -2b2bn1/r2pqp1r/4p1p1/ppp1k1Np/1nP5/P2P1PP1/R3P2P/2Q1KBNR w K -,34,931,29716,840246,26610771,773916341 -2k2b2/p4r2/1P6/P1p1pnpP/2P2N2/R4B2/8/4K2R w - -,37,965,34881,868137,30405503,732649957 -2b4k/8/2Pp1r2/p4pn1/P2Q1PPp/1P1N3P/5n2/R1K5 b - -,21,633,13546,419250,9446252,292195823 -1r3kn1/p1rp2p1/1p6/4NpP1/3q1P1p/1bpQ4/Pb1BP1BP/R3K2R b - -,48,1963,85869,3328420,142978751,5380204873 -6k1/7b/1p6/8/1n6/8/3K3n/8 b - -,20,108,2398,9825,225429,1043685 -rnbqkbnr/pp1ppppp/8/2p5/8/P2P4/1PP1PPPP/RNBQKBNR b KQkq -,22,551,13511,352927,9475535,257445174 -rnbqkb1r/pppppppp/8/8/3P1Pn1/4P3/PPP3PP/RNBQKBNR b KQkq -,25,795,20361,656227,17579556,576744381 -B1k2r2/n6r/p7/PP2B3/1P5P/8/4N2K/8 w - -,33,827,23329,577649,15520817,389363105 -4k3/8/3Q4/1P1P4/3P3P/n7/4K3/1N6 w - -,33,162,4719,32001,858939,6472089 -n2q4/3k4/3pN2b/1r1P1bp1/pPP2PPp/4P2P/p3K1B1/R3N1R1 w - -,30,977,28242,913433,26506034,869244486 -5N2/5B2/P5P1/2b4k/3p3P/8/2R1p1N1/2K5 w - -,25,309,7079,96114,2346566,33684558 -8/5N2/r3k3/8/8/1P1K1P1p/7P/8 b - -,16,228,3888,49838,834356,10219966 -2b1kr2/p6N/B2pp3/P3r3/5bPp/NR5P/2P2BK1/3Q2R1 b - -,31,1575,46728,2229656,65169220,3021106931 -r1b2bnr/ppp1kppp/2n5/1B1qp3/1P1pP3/3P1P2/P1PQ2PP/RNB1K1NR w KQ -,32,1143,37131,1292477,42770890,1479225383 -4rbkr/2n5/3P2p1/p3p2p/2pQ1P1P/P3PK2/7R/R1BN1BN1 w - -,45,1091,45813,1122380,46462886,1147269247 -8/N3n2R/b2kP3/P7/6P1/7p/8/1K6 w - -,17,287,5313,88510,1724818,29109569 -8/5p2/r2k4/p1r1p2p/1b6/p1PN2Rb/R2K1P1P/7B w - -,37,1007,34727,979947,32687862,950604742 -4k3/8/8/1K2P3/1N5P/2p2p2/R5r1/8 b - -,21,530,9170,211279,3599011,80025685 -bnk4r/7p/R3q3/p1Pp4/P7/3p4/3P2Kn/1NB5 w - -,17,588,8710,286272,4426952,143065319 -r1b1kbnQ/1p1pp2p/8/p4pp1/1qPn1P2/4B1PN/3NP2P/R3KB1R w KQq -,27,1023,27987,1007819,30643761,1073352919 -5k2/2N5/B5P1/1P1b4/7B/p7/8/5KR1 w - -,23,318,7397,84816,2154651,24992411 -5qn1/p2r4/P1P2P2/Bp1p2pk/3P3p/7P/5R2/3Q2KN b - -,3,117,3111,116583,2882885,104786180 -rnb3r1/pp5p/4p1kb/4npN1/P1PQ1PPp/2P1N3/4P2B/1R2KB1R b K -,27,1107,28563,1189135,30883060,1283226341 -rnNk4/4b1rb/1p2q3/6pp/Q2PPP2/P4N1P/bP3BK1/3B3R w - -,46,2046,85537,3753578,155233900,6783280929 -rnbqkb1r/pppppppp/7n/8/5P2/8/PPPPPKPP/RNBQ1BNR b kq -,20,457,10211,245210,6081133,154385219 -rnb1kb2/p1qppppr/1pp2n1p/7P/8/P1NP4/1PP1PPPR/R1BQKBN1 w Qq -,30,807,24603,702291,21660693,644282179 -3k2b1/2p1r3/3N4/p4pbr/p1Pp2R1/P1BP1P2/6q1/3K2N1 b - -,51,1113,48633,1060424,43967215,964808695 -r1b1kb1r/1pq1n1p1/2npp2p/p1p2p2/4P2P/2PP1P1N/PP1NB1P1/R1BQ1K1R b kq -,33,955,31153,930788,30422817,938862213 -rnbq3r/p2p3k/1p3p2/1Pbpp1pp/3P1N2/P5nP/2PB4/2R1KB1R w K -,28,969,27052,927652,25919749,888465566 -3rkbr1/2nbpp1p/5npB/ppp5/PP1P4/2P4Q/5P1P/1RN1KBqR w - -,36,1287,45016,1691561,59846615,2315788363 -4k2r/6pp/2p2n2/p2B1P2/1bP5/2Np3N/2R2K1P/1r4R1 b - -,35,1192,38460,1254312,40516107,1296829416 -4k1nr/2p5/P1r4p/P2p1ppq/1n1P1P1P/1P1bP3/R2KR3/1BBN4 b - -,38,765,28913,604281,22777530,498388939 -5k2/7Q/3R1r1P/1pp4r/1p6/P1b1n1KB/2N5/8 b - -,35,1087,31477,1014830,29413095,967258132 -8/1bk4P/p2R2r1/Pppn4/1P6/1P3B1P/1N3K2/1rBr4 b - -,37,1120,38897,1210817,41488265,1299050455 -r1bq1bk1/p5p1/1p1pp2r/1Pp1P1Rp/P1K2P1P/8/2P1PBB1/RNnQ2N1 b - -,27,1100,29994,1196993,33608117,1313289429 -r1bnk1n1/p7/q2p1p1r/2p1p1Pp/pPPN1pP1/3P4/4PP1R/R1QK1B2 w q -,38,1295,48099,1676557,61212990,2177712432 -rn1qkbr1/1pp1pppp/4b3/p2p4/3Pn1P1/P4Q2/1PPN1P1P/R1B1KBNR w KQq -,39,1217,45569,1424936,52588129,1658705667 -Q4N2/8/7k/8/1p4K1/3B3p/r7/8 b - -,17,584,8419,277116,4002459,129569446 -2b5/r1n3k1/1P1P1N2/NP1n2p1/p4p2/P1bK2P1/2r5/5R2 w - -,32,1385,38455,1641134,43474986,1812169317 -r3k1n1/p7/q1bpn2P/2p1pp1p/pPPN1pP1/3P3R/1QK1PP2/2R2B2 b q -,42,1470,58548,2074049,79693536,2844244211 -8/8/r6b/P3p2N/1nk3pp/K1PBP3/4b3/B7 b - -,5,72,1904,29157,786112,12796696 -1r3B2/4r3/p3Nbkp/P2B4/1P2P3/2Rp4/3K4/8 w - -,33,944,28562,792358,23645346,641900959 -2br1bk1/1p2p1Bp/3p3n/1R4p1/2P1pP2/6PN/3K3P/5B1R w - -,39,768,26391,550796,18238243,407911461 -2k3r1/6n1/8/8/1K4n1/8/8/8 b - -,19,149,3292,20343,492672,3009898 -8/5b1P/6P1/8/8/3k4/8/3K4 b - -,13,105,1314,15092,189534,2763067 -8/1B1k3N/p2p1b2/P3p1P1/1Qr4p/N1P4P/8/1R3K1R b - -,22,780,13619,522522,8871122,354016101 -rnb2br1/p1ppkp1p/1p2Bq2/6p1/2P2B2/NP1PP1P1/P4n1P/RQ2K1NR b KQ -,43,1199,48673,1438385,57555102,1786446011 -1k6/8/3r1pP1/p1p5/P1P2q2/1P3p2/N4K2/R1R5 b - -,31,403,13112,199586,6327111,108817692 -3k1br1/rp3p2/1n1p2pp/pPp1pP2/3P1Q1R/P1N5/1BPNP3/3RKB2 b - -,28,1159,30097,1270739,32025400,1363842327 -r3kb1r/1b1n2pp/p1p4n/4p3/1PPp1B2/2N4B/P2KPq2/RQ4NR b kq -,41,1411,55574,1946565,76815080,2755344081 -1R6/6p1/8/6k1/3K2n1/8/8/2qb4 b - -,33,438,14577,176665,5951942,72194402 -r1b1k1r1/p1p1bppp/n2p4/1N2p1B1/P2PP2Q/8/1PP2PP1/R4KNq b q -,33,1230,40206,1490246,49869256,1825880329 -6b1/3rk3/np5N/P2PPP2/6P1/6BK/b1B5/7R b - -,23,663,14475,413438,9616741,276663699 -rn3b1r/1bqpp1k1/p7/2p2p1p/P2P4/2N1P1P1/1pK1NPP1/R3QB1R b - -,43,1395,57901,1816208,73483488,2295253752 -3N4/7k/7P/P3P1B1/1pK1b1P1/4p3/8/8 b - -,17,267,3769,64443,869162,15555113 -2rb4/r7/6k1/1p6/3p1KP1/R1N2NB1/8/1r6 b - -,44,1206,46058,1228059,46344569,1227865214 -8/7k/3bP3/7p/P3P2P/2NN4/8/6K1 b - -,16,306,4139,76844,964696,17591958 -4n1r1/k7/8/p3p3/2B3p1/8/1b2K2B/1N1r4 w - -,19,591,11265,349895,6911047,217597069 -7N/3k1B2/8/2P5/8/8/nK6/8 w - -,17,129,2124,16697,271599,2344623 -3r4/k7/8/8/3P4/P3K2R/8/3N4 w - -,21,322,7082,109525,2412924,37965041 -1r3b2/1Bn5/p2pbk2/P1p2p1Q/3P4/P2K1pp1/3B4/R5NR w - -,46,1121,47264,1185083,49393927,1265968142 -r3r3/p1p2kp1/n3b2p/P3PNb1/4P3/1PP2PP1/4N1q1/1R2K3 w - -,20,804,13765,573582,10051509,422670213 -r1bk1b1r/1p2pP1p/pq1p2p1/3p2P1/nP3PR1/P1PKQ2B/2N4P/RNB5 b - -,29,757,21648,609422,18102246,540348918 -2kNN3/5r2/7P/1P1n2p1/8/4r1p1/2K5/8 w - -,15,512,7303,231451,3380632,103675425 -k5n1/2P5/4K3/rp1PR2p/1p4NP/1PR3q1/8/8 b - -,27,696,18777,474529,13099934,334266220 -6r1/6R1/1n5k/8/8/7K/3p2B1/1b6 b - -,27,585,16301,353522,10406245,221654281 -r1b1kbnr/1p1pp2p/2n3p1/p1p2p2/P1q2P2/3P2PN/3BP2P/RNQ1KB1R w KQkq -,26,1001,27337,1006118,29031447,1048060504 -2k1rbn1/3R4/2P5/3p1P2/3N4/8/2K5/5n2 b - -,23,498,10803,231286,5286788,111252577 -3k4/8/5N2/8/5P2/1P5p/7P/3K4 b - -,3,45,266,3559,20102,269907 -rnbqk2r/p2pbp2/1p2pn2/P1p3p1/1P1N1P1p/3PP3/1BPK2PP/RN1Q1B1R b kq -,32,1191,37834,1398440,44693630,1646781409 -Q7/5k2/p2Pn3/P3p3/P1p5/2N1bK2/8/3R1B2 b - -,23,778,14203,492330,8611308,302056596 -8/1b6/1k6/8/6pp/2K5/8/r7 b - -,32,228,6705,33631,958918,4953316 -2B5/k7/1r6/8/4K3/6p1/3b4/1N6 b - -,26,387,9605,142440,3468146,52784424 -1k6/5n2/1p2r3/6p1/K3b1P1/2pp3N/1R5P/8 w - -,19,572,9733,295292,5108142,152040282 -k1b3n1/4b1b1/3p4/3P1Pp1/2P3Pp/p3K2P/5R2/1B1NN1R1 w - -,31,706,20059,442218,12196892,274254576 -8/4R3/6R1/2p2K2/2Pq4/8/3N4/3k4 b - -,24,582,12096,297861,5984203,147589287 -7r/R7/5P1k/2p2P2/7P/1b4Pp/2R4K/r7 w - -,28,820,20556,580549,14196509,398880119 -rnb1k2r/p2p1p1p/1p6/6p1/1bP2qP1/1PNPP2n/P2KN2P/R2QB2R b - -,42,909,36986,884745,35453372,925696029 -8/6b1/3k4/3b2P1/2P5/1p4p1/1NN1K3/1R6 b - -,28,644,15767,344922,8017108,173917970 -5b2/8/8/Pk2p3/7p/1KP1Pr2/1Bn1b3/7N w - -,10,291,2992,90496,1013174,30909673 -3k3r/1R6/7n/2Pp1PN1/p7/3K1N2/3b3P/6r1 b - -,31,998,27346,789737,22121138,597470948 -r2k1b2/n7/p2p2Q1/P1pP4/8/P2KBB2/6p1/R5NR w - -,52,773,36885,594436,27314779,486519320 -r7/8/5b1k/1p6/2Np2P1/1R4B1/8/1r3K2 w - -,5,173,4616,140147,3573384,104289739 -k7/2r2N2/5P2/6r1/2pK4/2P5/8/4N3 w - -,12,292,3733,87408,1192532,27772309 -rnb3nr/2p1p3/4k3/ppPp1pq1/4P1Q1/N5PP/PP1bKP2/R1B2BNR b - -,40,1052,37630,1083773,38177755,1167510369 -4kr2/7p/7P/ppp5/1Pn1p1r1/P1b5/3R3K/N4B1Q w - -,28,1055,26276,961970,25188035,897165799 -2r5/5b1r/2nP1k2/pP3pp1/P3RPPQ/b3P3/8/4KR2 w - -,29,970,28337,975485,29048858,1000133630 -r1bq1bn1/pppk1p1r/3p4/6pp/3PPpnP/N1P2PPR/PP2K3/2RQ1BN1 b - -,34,925,30150,864286,28304050,844107148 -5kn1/8/2K5/5P2/1P4p1/pN3r2/8/5N2 w - -,20,371,6324,121231,1982402,39147627 -8/1K6/8/1k5P/8/1b2b3/8/R7 w - -,19,425,6973,146856,2392891,48992438 -B4B2/2k5/2b4P/2K1P1P1/8/8/8/8 b - -,15,218,2540,44877,509516,9847215 -b1N1k3/8/8/6r1/2pB1P1n/4p2B/p7/2KR4 w - -,31,945,27611,790785,22757866,643113553 -rq5r/pb1k2bp/P1p2B2/3pp3/1PBPP3/6P1/1P1NKn1P/6NR b - -,34,1012,33108,974420,31528277,922806545 -8/1Q6/8/2k5/6pp/8/r7/2K4b w - -,25,454,9390,175501,3687201,69440864 -r1bqkb1r/p3p1pp/npp2p1n/3p4/2B2P2/N1P1P2P/PP1P2P1/R1BQK1NR b KQkq -,30,984,29426,959297,29475029,962760157 -3rnb2/4p2p/3k3n/p7/2p2prP/2ppR2K/PB1NB3/RN1Q4 b - -,33,1024,30851,1001429,31074323,1041446023 -k7/8/3N4/3K4/8/2P5/4r3/8 w - -,13,210,2571,39067,463391,7119280 -8/8/2P5/7k/K7/7p/1q6/7Q w - -,15,321,5269,106915,1990778,40192021 -2b2bn1/1k4b1/3p4/3P1Pp1/2P3Pp/p3K2P/4R3/1B1NN1R1 b - -,22,612,13947,388284,9118411,251773828 -rnkq1bnr/p3ppp1/1ppp3p/3B4/6b1/2PQ3P/PP1PPP2/RNB1K1NR w KQ -,36,957,33542,891412,31155934,840073244 -q1k2b1r/3bp1p1/rp1p4/n1p3Np/1PPPPpn1/R5PB/3NKP2/B3R3 w - -,39,1535,56064,2125838,76506043,2875122936 -8/1k2rb2/8/p7/8/8/8/5K2 b - -,27,85,2367,13192,368227,1795703 -8/2k5/P1r5/1p6/8/1p6/2r1N1Kb/8 w - -,7,212,1862,58613,554909,17340732 -rr6/1b5p/p1p1B1k1/2bNpq2/1PP5/3p4/P3P3/2BK1RNR b - -,39,1508,51748,1965753,66913663,2513493732 -3Q4/3n4/3k4/7P/3P4/N3K3/8/8 w - -,28,138,3867,29695,816757,6513226 -rnNk2b1/6r1/1pQ1q3/6pp/1b1PPP2/P4N1P/1Pp1K3/1RBB1R2 w - -,45,2236,92385,4398943,177476798,8209857757 -8/4R3/6R1/2p3q1/2P5/5N1K/8/3k4 b - -,19,437,8315,207759,4090921,102777008 -2N2R2/1K6/p3kN2/p7/P7/N7/3n4/2r5 w - -,26,561,14930,287056,7885565,148446946 -2kr4/2b5/p7/PppR1pP1/5B2/3K3b/RP1Q4/2r5 b - -,30,769,22236,631463,18304999,550724916 -5kr1/8/B3nn2/2N5/8/8/1K6/8 w - -,22,527,10502,263997,5032154,129087596 -8/8/8/2n2k2/1P6/7p/2K4p/7R w - -,16,260,4190,67227,1109259,18176616 -1n1r4/6R1/5n1b/2pp1kp1/P1p4r/2K2P1P/6B1/1b6 w - -,16,505,7859,240946,3868434,118507339 -3K4/8/2q5/P7/2b2R2/8/7k/8 b - -,37,462,14062,185228,5433924,74168918 -8/4k3/P5P1/3p2N1/2Q3B1/4p1pP/4K3/1R2N3 b - -,8,381,2315,102620,644942,26839784 -1r1k1bnN/8/3p4/1q1Pp1p1/2b2pBP/5P2/2R2nR1/4K3 w - -,24,925,21380,841270,20127118,798902725 -1k4n1/1p2B1bp/3pp3/3Q1p1P/2pP4/1R6/4P1B1/K5R1 b - -,21,923,16135,704692,11672207,506954282 -8/1K6/8/8/8/2kp4/8/6n1 b - -,11,88,1056,5930,74960,469834 -5r2/1p6/p1kR1Q2/2p1Pbrp/R1K2pnP/1PP2P2/4N3/1N6 b - -,1,41,1104,38374,1012992,34923552 -rnb1qbnr/6pp/Pp1kp3/2p2p2/P1p3P1/BQN2P1P/3PPKB1/R5NR b - -,35,1421,44754,1734554,54146397,2036202854 -5k2/rp6/P4B1r/R2pp1K1/8/1n4P1/1p3b1P/1N2N3 w - -,26,773,18845,583930,14490257,464670880 -r1bq1b2/p2n1kp1/1p1pp2r/1Pp3pp/Pn1P1P1P/2K1B2R/2P1P3/RN1Q1BN1 b - -,36,914,31990,868968,29821362,859625153 -2r2N1k/8/1N6/1B4n1/P2P3p/KPp2PQ1/7P/7R b - -,20,878,15210,648501,11108139,461245084 -8/8/P2Rn3/k7/1p6/7P/2B1N1K1/5nR1 b - -,14,423,5420,179754,2336672,80072181 -8/6k1/8/2P5/2K5/7p/7p/2R5 b - -,12,202,2255,40135,506867,8661558 -1r6/8/R4P1k/2p2P2/1rR4P/1b4Pp/7K/8 w - -,26,625,15674,414173,10103837,281501758 -r1b1k1r1/p1p1b1pp/n2p1p2/1N2P1B1/P3P3/2P5/1P3PPQ/R4KNq b q -,31,1113,33822,1176938,37085293,1270416062 -8/2p5/rp4P1/1pk2pNp/5P2/3bn3/3N1K2/8 w - -,18,407,6261,151819,2300514,57216565 -N4Q1k/8/8/8/4B3/1p3K2/7p/8 b - -,0,0,0,0,0,0 -k7/6b1/7N/2b5/3N4/1K6/8/7R b - -,17,461,8146,214612,3960658,102967659 -5r2/nk3B2/p7/PP5r/7P/1PB5/7K/2N5 w - -,28,702,18322,468713,11870158,307870283 -4rb2/1kp1p3/4b1r1/p1q2pp1/p1Pp1P2/3P1P1P/PB1K2B1/1N3RNR w - -,21,778,16303,600857,13019530,481246911 -1Nk3nQ/7p/4pppb/3r3P/2p1PqP1/B4P2/P1bP1K1R/R7 w - -,36,1514,48255,1888637,61176911,2317520789 -8/8/1k2P3/4b3/4B3/1K3p2/Q5P1/8 w - -,33,546,17202,238025,7458522,99350287 -rn2b1n1/4b1kr/3pP2p/8/pP2PppP/p1R3P1/2KB1P2/1NN4R b - -,28,876,24692,767455,22031994,684864497 -rnbqkbnr/pp1ppppp/8/2p5/7P/N7/PPPPPPP1/R1BQKBNR b KQkq -,22,459,11280,263160,7036823,180587185 -rnb2bnr/pp2p1kp/6p1/q1pp1p2/PP3B1P/2NP4/2P1PPP1/R2QKBNR b KQ -,27,1011,27577,989802,28263147,999297045 -6n1/2p1k2r/P2r3p/P2p1pP1/1n1PP2P/1P2K2b/B7/R1BqR3 b - -,44,666,28743,476606,19786683,355309278 -1rb1q3/p2p2p1/P1p1R3/1pPn1P1k/P2P1b1p/B6P/2R5/1NQ1K3 b - -,37,1128,38061,1233356,40031555,1333721041 -r2k1bbr/p3n3/1p1B1q2/5p1P/PpPp4/2Q2N2/3PPPBP/RN2K2R b KQ -,36,1423,50450,2010203,72481104,2901142689 -3k4/r7/Pp1n4/2p4P/2PNB3/3R2p1/8/3K4 w - -,31,662,20668,396727,12117013,230117640 -5r2/1k6/1P6/8/K5p1/7n/8/8 b - -,25,118,2615,15008,328754,2013955 -r1b3rk/1p6/nb6/Bq1pp1p1/P1pQ3p/4n1PK/2PN3P/RN5R w - -,2,84,2188,90540,2575658,106845103 -8/k4r2/4p1p1/p2n3p/PBp4P/2rB1P2/1R1R2Kq/8 w - -,2,78,1891,65720,1712152,57611540 -2k5/8/2b5/3p4/P2n2pp/2Q2B2/1K2r3/8 w - -,7,183,4048,102750,2514129,62687449 -8/8/3r4/2k5/6p1/7r/8/6K1 b - -,36,112,3792,15240,499441,1889149 -5n1k/3B4/6p1/4p2p/7P/5Kb1/8/8 b - -,13,158,2230,26624,395401,4780238 -3r4/4k2n/8/1Pb3P1/2P5/p6r/5RK1/4N3 w - -,20,719,12370,422575,7569345,251075058 -2b1k1n1/r2qbpr1/n1p1p2B/1p1p4/Pp5P/N1PP1P1B/4P3/R2QK2R b KQ -,38,1356,51467,1846766,70516554,2548443462 -k7/8/2K5/6b1/8/6p1/2B5/8 b - -,12,182,2190,31431,393669,5484872 -8/4k3/8/2n2Q1p/7P/1r4R1/8/2K5 b - -,23,788,13735,427572,7419724,227867699 -1r1b4/1k6/1p3R2/1P3p2/B7/n3p1K1/PN6/4R3 w - -,30,436,11916,202063,5649431,109324578 -1r6/8/8/k7/N2P4/P4K2/5R2/6r1 w - -,17,506,9687,260149,5118473,130711127 -6b1/k7/2K2R2/8/8/8/3b3P/8 w - -,18,319,5653,99550,1734621,31068878 -3rnbr1/3kp2p/7n/p1p5/5p1P/2pp1R1K/PB1NB3/RN3Q2 b - -,32,815,26573,780843,25903213,833537167 -5kn1/8/3P4/5P2/p1R3pb/P1NK2N1/5r2/8 b - -,22,566,12132,307334,6661806,164619055 -4n1kr/4q2b/1p2p1p1/p3B2P/2Q1BP1P/R2p4/1P1N4/1N3K1R w - -,56,1365,72195,1629953,81850333,1875049435 -b2k4/b3r3/2P4N/7P/PK2p3/8/8/8 w - -,12,229,2598,54337,648139,14162704 -2b1kb2/3Np3/P5p1/B2PP2p/2PR2r1/1r4P1/5P1P/n1K4R w - -,32,914,26081,735386,20699297,585778273 -8/2p5/1p4P1/1pk2p1p/4bP2/4n2K/r2N4/8 b - -,35,331,9561,87344,2610667,25520911 -8/p7/Pq6/1K3k2/N2P3p/8/1B6/8 w - -,2,35,382,6675,79466,1558422 -rn1qk1nr/p3pp2/b1pp4/1p4p1/1Q2P3/NP1P4/P1P1NbP1/2KR1B1R b q -,34,1185,40775,1408223,48737765,1684947227 -8/8/k5pr/B3p2p/P3R2P/3p1P2/6KR/8 b - -,7,168,1924,48860,685670,17692526 -1r3br1/1bNB4/p1p2Bkp/2P5/1PR1P3/3p4/P2K4/5qN1 b - -,32,936,30695,878281,29931256,849478376 -3k2nr/p4p2/1pp1pP1b/1n5p/8/1BP2rPP/PPbN2KR/R1B3N1 w - -,21,813,18041,677185,16135109,593495217 -5k2/6p1/pp1Nn1q1/1R3p2/P3PP1p/1b5B/1b3K1P/2q4R b - -,51,1137,54568,1283662,60532052,1483142856 -8/2k5/1P3B1p/5p1r/7R/3P4/4NK2/2b5 b - -,7,243,3431,100930,1577800,42476676 -rn2k2r/4n2p/1p2p1p1/8/P2q2P1/4P2P/3b1KbR/3r1RN1 b - -,61,706,39885,569813,30985287,497458497 -r1bqkb1r/p2ppppp/np3n2/2p5/P7/5P2/RPPPP1PP/1NBQKBNR b Kkq -,22,437,10785,236461,6379236,152244454 -4Q3/3Q4/8/2k5/8/3K4/8/5B2 w - -,45,86,4225,11111,551351,1407756 -3k4/4R3/8/4b3/p6p/3K1B2/2r2P2/r7 w - -,24,786,17404,530674,11680731,347334154 -k3r3/r7/1P6/8/6p1/8/2K5/6n1 w - -,10,278,1711,43734,274876,7089235 -2b3n1/r2p3r/2nk2p1/pPbN1pp1/P2p1P2/6QP/2RBP3/4KBNR b K -,30,1220,34763,1321764,36952489,1372322763 -6n1/8/B4n2/Pp1p1P1p/1k6/1P2R2P/2p4b/2K2RN1 b - -,19,460,9079,220368,4527543,113692193 -2k4r/p2n1p2/1pp1p2b/1n5p/2B2B2/2P2rPb/PP5K/R5NR w - -,30,1187,34648,1367948,40113497,1573545057 -2bq1bn1/1rpkp3/n2p3p/3P1pp1/ppP3P1/PPB1P2P/3QNP2/RN2KB1R b KQ -,20,636,14063,465740,11130165,380417426 -1rb1kb1r/pp1pp2p/2p2Ppn/q1nP4/5PP1/P1P4B/1P1Q3P/RNB1NK1R b k -,33,907,29965,891707,30025292,939070516 -2b2b1r/1r1k3p/p5Q1/npp1p1PP/2Pp4/PN3K2/RP2B3/6N1 w - -,36,612,20071,400053,12652808,279681478 -8/5P2/8/4bB2/rpQ3Pk/8/4K3/2R5 w - -,48,1088,50205,1065045,48522929,1029412672 -r1bNkb2/p2p1r2/n6p/1B1pp1pP/5p2/PQ2P2R/2PB2P1/R3K1N1 w Qq -,48,1127,53129,1269315,58402716,1430777984 -rnbqk1nr/ppppp1bp/5pp1/3N4/8/5P2/PPPPP1PP/R1BQKBNR w KQkq -,26,495,13057,274963,7501937,172156341 -rnbqk1nr/p2p3p/1p5b/2pPppp1/8/P7/1PPQPPPP/RNB1KBNR w KQkq c6,29,643,19615,476024,15269657,394866509 -rnbqk1nr/pppp3p/7b/3Pppp1/8/P1N5/1PPQPPPP/R1B1KBNR b KQkq -,21,608,14462,450755,11474641,377497753 -1B6/1r5k/1bB1N3/Pp1R4/7p/3K4/8/8 b - -,22,768,15102,522504,10278659,354545423 -1rbqkbnr/pppppppp/8/8/8/3BP1Q1/PPPP1PPP/RNB1K1NR b KQk -,19,733,15206,594607,13496625,527886272 -8/3P2k1/p7/P7/N1p1p1B1/8/5Q1R/5K2 w - -,48,229,10633,52453,2311576,12107203 -1n6/8/3k4/7P/3PK3/N7/8/8 b - -,8,94,853,10579,103525,1328637 -3N2k1/8/2b4P/P3P3/1K3BP1/4p3/8/8 b - -,15,268,3407,62453,784144,14627568 -3N3k/Bnr4b/7B/8/3K2p1/6P1/8/7R w - -,28,555,14588,300199,7964429,169473972 -6k1/1N1R4/8/1p1pP1BP/P7/3pP3/2bK2P1/8 w - -,28,246,6796,58165,1584589,13955938 -2b1kr2/1p1p1p1p/r1nq3b/pQP2PB1/P2ppN2/2N2P2/1P2K1BP/R3R3 w - -,50,1451,67334,2000986,90420788,2747068338 -8/8/r6b/P3p3/1nk1b1pp/K1P1P3/1B6/7N b - -,38,246,8542,74867,2469417,24788494 -7r/1k1n1p2/1p2p3/pPp5/B5K1/2n1b2R/Pr1N4/4R3 w - -,31,1454,39486,1715482,46683246,1915050203 -8/7k/2R1P3/7p/4n3/8/2B1K3/7q b - -,18,229,4886,73706,1770107,29621916 -2k2B1r/7p/1r2p2P/p2npBp1/1P3P1P/P2p3K/N7/R1B1R3 b - -,30,933,26838,855983,24338294,794728858 -8/2N2r2/4N2k/p2K1p2/P4P2/6p1/8/8 b - -,11,158,1940,28522,394244,5671896 -1k6/b7/2b4p/2P4P/4p3/P7/7N/3KB1r1 w - -,8,188,2414,57578,817316,20060063 -rnb2bnr/2pkp1Q1/p2p2qp/1pP2p2/2N5/4P3/PP1P1PPP/R1B1KBNR w KQ -,40,1053,41060,1101005,41749488,1149235382 -k7/r7/8/8/2p2K2/2P5/8/2N5 w - -,12,181,1982,29839,321549,5052387 -6R1/8/rn1b4/P3p2p/2kP3p/2PbP3/1K6/BB3N2 b - -,28,680,16989,386325,9821066,222582860 -5N2/k5b1/8/1P3R2/1K4nP/8/8/8 w - -,23,393,8223,134298,2767277,44934279 -R7/8/3k4/1p4r1/2n3p1/2K5/6r1/8 b - -,34,552,16670,233149,6940852,93515748 -rn1qkbnr/p1p1p2p/4bp2/1p4p1/2p1P3/NQ6/PP1P1PPP/R1B1KBNR w KQkq -,34,1081,35178,1117318,36541695,1172623510 -2b3k1/r1nN4/1P1P4/1P1nb1p1/p4p2/P2K2P1/3N2r1/5R2 w - -,29,1109,29136,1119312,28669196,1100324599 -2N3n1/8/4P3/P1k3N1/7p/1K1b4/2N3P1/6R1 b - -,17,468,7492,213215,3374258,98137290 -r1bq1bkr/p5p1/1p1pp3/1Pp1P1pp/P1K2P1P/7R/2P1PBB1/RNnQ2N1 w - -,45,1165,48863,1338103,53793270,1529693516 -4k3/3n4/3R3p/3p1NpP/pp1P2p1/8/2P1K3/R6Q b - -,12,555,5690,245256,2643351,108255228 -8/8/8/1p3k2/3p4/1p6/5KB1/8 w - -,15,138,1959,18301,257152,2466124 -3k2nN/7B/3p4/3Pp1b1/5R1R/1r3P1p/7q/2nK4 b - -,41,837,31329,642039,23934772,502990050 -r1bnk1n1/p3p3/1q1p1p1r/2p3Pp/pPPN1pP1/3P3B/4PP1R/R1QK4 b q -,38,1311,48570,1679934,61104658,2132199231 -k7/8/8/8/2pK4/2P1r3/8/2N5 b - -,15,109,1649,14729,232835,2265700 -8/3N4/8/8/3k4/rP3P1p/4K2P/8 b - -,10,119,1784,20733,314827,3605364 -B6k/8/2b3KP/6R1/8/8/8/5n2 b - -,16,270,3675,70339,941681,18877123 -4q3/3R4/7B/4P1P1/1K2k3/Pp6/8/8 b - -,20,427,9235,172783,3824897,69242328 -6br/5k2/2B4p/r1P5/3p2KB/1P2p2R/R3n3/8 b - -,21,715,15268,509657,11845830,389257465 -r2qk1n1/p2p2p1/1prb2N1/5p2/2bp1PPp/2p1B3/P1Q1P2P/RN2KB1R w KQq -,33,1300,42886,1702304,56890882,2254286176 -rn6/p2p2qk/1pp1p1p1/1R3p2/P4P2/N7/2K1QPb1/2B3N1 b - -,30,1000,29323,983932,28739194,954922302 -8/4k3/8/2PPR3/1K2p3/5rp1/6p1/8 b - -,5,65,1122,16510,295812,4619378 -R7/2k1b3/4r3/pr3p2/4p2p/R1P4B/4NP1P/4K3 b - -,34,969,30045,861834,25907459,752825704 -8/8/8/2kr4/6p1/7r/8/6K1 w - -,3,99,424,13649,49530,1581838 -1b2b3/4P3/6r1/7P/2Pk4/r7/4pK2/8 w - -,5,230,1328,57202,397717,16170553 -3r1k2/8/1p2B2N/1P2b3/P5K1/6R1/8/b7 w - -,28,745,20460,511779,13821214,343622809 -6b1/5kPR/8/1P2BB2/8/8/5K2/n7 b - -,5,180,1790,62411,693571,23557995 -3R4/4Nr2/1k2r3/1P1n4/6p1/8/1K4p1/8 w - -,23,759,15841,530768,10662729,359371717 -rnbqkbnr/ppp1p1pp/8/3p1p2/6P1/1P5P/P1PPPP2/RNBQKBNR w KQkq -,21,544,12608,348037,8754362,256143826 -1rb1k1r1/p1p1p2p/1p2P2b/Q2p2p1/NP1B1pP1/P1nP1Pn1/4N2P/3R2KR b - -,32,1048,31177,1040883,29924203,1017719808 -1N4Q1/8/1N3k2/5r2/3pb1K1/3P4/5Q2/1R6 w - -,56,653,29979,437178,19844874,312556404 -Br2rB2/b7/p6p/1N5k/PPp1P3/3p4/8/2RK4 w - -,23,606,14401,398370,9716063,275222875 -R7/3k3p/2b4P/3p3r/p7/1pb2Kp1/8/8 w - -,17,466,6740,186826,2586006,72371149 -2kr1b1r/1b1p4/2p1p1np/P4pp1/p2BP1P1/N1P2QP1/3PB3/RN4KR b - -,25,1006,26228,1043357,27919638,1106193110 -8/4Bk2/B1n4p/Pp1p3P/P2pPp2/5R1N/b2K1PP1/Rq6 b - -,31,757,21031,535346,14272882,377967219 -1r1k2nN/7B/3p3b/3Pp3/1R4Rp/5P2/7q/2nK4 b - -,37,1088,37738,1026450,36011131,943450425 -r1bqkbnr/p3pppp/np6/2pp4/P1PP4/R2BP3/1P3PPP/1NBQK1NR w Kkq -,39,1047,40467,1169083,44896456,1374695717 -rR6/2b3kr/3pb3/1P1NN2P/p3nP1P/8/8/1KB4R b - -,29,1070,30922,1097133,32350744,1123801117 -rnbqkbnr/pppppp1p/8/6p1/8/4PN2/PPPP1PPP/RNBQKB1R b KQkq -,21,586,13334,394621,9694987,298447565 -8/r2N3r/2b1P3/P3b2P/2pk4/3Pp3/1p2R3/3K4 b - -,41,734,29636,534017,20685051,379123620 -1K6/8/1P4k1/8/8/8/8/8 w - -,6,48,272,1845,12468,83011 -1r4nr/2p1p3/n3b2k/1p2P3/1b2B1pP/3B2P1/P1NqNPK1/4R2R w - -,38,1421,52767,2066184,75165867,3021179641 -1r1qkbnr/1p1bppp1/1pn5/2p4p/2PpP3/PN1P1PPP/1P6/R1B1KBNR b KQk -,25,604,16810,426538,12665804,333569116 -k7/2r5/8/8/2p2K2/2PN4/8/8 b - -,14,186,2837,35316,556155,6401857 -7k/8/8/2P5/3K4/7p/7p/7R w - -,16,78,1423,12591,222875,2523296 -1n1rkb2/p7/2n1b3/8/pP1p4/4RpK1/1N3P2/B5n1 b - -,26,424,12660,209243,6672802,115596549 -5n1k/3B4/6p1/4p2p/7P/5K2/8/4b3 w - -,13,195,2376,36938,455042,7259363 -7B/R1p5/Pn2P1p1/5k2/8/1PrN4/4KN2/b7 w - -,28,565,15064,323289,8712791,196538969 -1n6/2p5/1p3N2/8/1pk2P2/5K2/8/8 b - -,13,203,2469,33500,400985,5234102 -r4br1/8/3k2pp/P1nnp3/6P1/2PPP2P/4b1B1/RNB1K3 b Q -,40,877,33568,756910,28087359,648643302 -2B5/2r1b1k1/8/6r1/4b3/2p5/1n1p1K2/8 w - -,10,544,5507,286950,2866061,145217333 -r3kb1r/2p1pp1p/n5pB/pp1p1q2/1P1Pn1b1/PNP2Q2/4NP1P/1R2KB1R b q -,41,1554,64502,2403795,99415978,3661826380 -n1kq1b2/8/3pN3/1r1P1bp1/pPP1PPPp/7P/p1N1K1B1/3R2R1 b - -,33,1245,41818,1463252,50111373,1655790737 -1N1k4/P5b1/4p1p1/2PP3p/R4BrP/8/2nKb2R/1r6 w - -,33,1439,45057,1840204,56466858,2200001652 -2R5/1B1nk3/5r2/2p3bn/P2pb1r1/2p5/8/3K4 w - -,18,838,13911,612383,10446515,445393585 -r1b1kbnr/p1p2p1p/4p1p1/1p1p2q1/4P1PP/N2B4/P1QPKP2/R1B2R2 b kq -,41,1144,42044,1238842,44463477,1370876133 -1k4n1/b7/5P2/3b4/3p1bPp/6RP/4KN2/1B6 w - -,25,757,16968,487323,10978571,304985390 -1n4nr/3r3p/7b/pppB2kb/3pP1Pq/3P4/PQPK3B/RNR5 b - -,31,886,28262,821000,27358004,811083393 -8/K7/8/1P6/8/8/8/6k1 b - -,5,30,174,1044,6587,42967 -2bqk2r/1r1pbppp/ppn5/Q1P1p2P/2P3n1/4PP2/P2P4/RNBK1BNR b k -,35,1050,36640,1108358,38816777,1196458524 -8/7k/2R1P3/8/4n2p/5q2/2B5/4K3 w - -,15,363,4938,127758,2098496,55055043 -rn2qbr1/N1pkpbp1/Qp6/5P1p/2pPPP2/3B3P/PP1N4/1RB1KR2 b - -,21,695,14859,514359,11937719,425602563 -5b2/8/rn6/P3p2p/2kP2Rp/2P1P3/1K2b3/BB3N2 w - -,27,577,13661,322047,7601839,189928128 -7b/8/1p2k3/PP3N2/4Kb2/8/1R6/5B2 b - -,21,573,10826,283569,5323993,136494122 -1n1R4/4k3/5r1b/2pp2Pn/P6r/2p5/4B3/1bK5 b - -,45,905,34749,676086,24860909,473522335 -4n3/5Bk1/5R1p/pp1p2pP/3P2p1/R5N1/2P2KQ1/8 b - -,9,372,3398,136101,1287634,50873022 -5r2/p6r/1Q6/q3pk1p/PB3pp1/1PnPP2N/1R1K1PP1/1N3B1R b - -,40,1505,54434,1992851,71884126,2649499976 -8/7b/2P1Pn2/Pk4N1/7p/K1p5/6P1/3N2R1 w - -,19,375,8029,154853,3587438,68676468 -rnb1kb1r/p1pp1p1p/1p2pq2/6p1/5Bn1/NPPPP1P1/P4P1P/RQ2KBNR b KQkq -,40,1045,41188,1149535,44827444,1314968248 -4b3/4k3/4P3/bP3R2/p6P/6n1/1K6/8 b - -,23,422,9394,161871,3610310,60415451 -1n2kr2/r1bb2np/pp2pq2/1Npp1p2/2BP1pPQ/PPP1P2P/7K/3RB1NR b - -,35,1069,33250,1053531,33092462,1079560279 -r4b2/pBqb2k1/1p2p2r/1Pp1p2p/P1K2P1P/8/2PQP2B/RNn3N1 w - -,35,1142,37936,1221717,39683151,1281839652 -r2k1b2/p3pn1R/n7/2Qb4/pP1pp3/3N1N2/1B3Pp1/1R4K1 w - -,48,1119,52257,1290623,58785962,1512068519 -8/8/P3K3/8/8/8/2b1R3/5k2 w - -,17,162,2885,29872,541861,6048770 -r7/2b3r1/1N6/2p1PR2/P3b2P/3kp3/1p1P4/3K4 b - -,42,694,28661,488211,19356588,335150038 -2Bk4/2N4N/1Q6/P2p2P1/1R3b1p/3Kp2P/6R1/2r5 w - -,51,997,45762,843164,38120071,701351216 -7R/7p/5knP/K1p4P/3r1B2/5p2/8/8 b - -,24,466,9936,191471,3988854,78349951 -2k5/8/1P6/5p1p/Nb1P4/8/7r/B4K2 b - -,25,202,4252,44351,938846,11101996 -Rn2k3/P7/2N5/8/5K2/1p5P/8/6R1 b - -,4,140,901,28853,230976,7073053 -8/6b1/6r1/P3pb2/1nk3Np/K1P1P3/8/B7 b - -,33,348,10253,109696,3244070,35680310 -5n1k/8/6p1/4p2p/6BP/4b3/6K1/4r3 b - -,28,337,9285,99847,2720246,29770817 -3k4/8/8/4P3/1N1K3P/2p2p2/r7/R7 b - -,21,503,8511,193765,3218768,70787637 -rnbq1r1k/2ppn2p/1p1b2p1/p3ppB1/1PP4P/1N1P1R2/P3PPP1/R2QKBN1 w Q -,36,951,32921,907969,31604488,912570681 -3b2k1/8/8/8/8/2K3p1/3pb1P1/2B5 b - -,29,236,6318,52116,1357691,12926059 -5bnr/1p3k2/8/q3p1pp/ppN2PP1/B1P1p2P/P2PK2R/4R1NB w - -,37,1213,43752,1423234,50072736,1633756774 -8/8/1r5b/P3p3/1nk3pp/K1P1P1N1/2B1b3/B7 w - -,22,585,10957,287677,5057569,132126664 -8/rk6/5pP1/p1pP4/PNPq4/1P3p2/1B6/1R2K2R b - -,26,439,11579,229194,6087988,133527398 -5N2/8/3rnk2/8/P2P4/KPpQ1P1p/7P/5B1R w - -,28,481,14790,255123,8063915,143604087 -6r1/6k1/n7/8/6K1/5B2/2bp4/3R4 b - -,27,446,13195,268630,8163109,171661944 -r1bn1r2/2k3p1/6p1/pP3p2/4P2P/1P1P3R/2P1NB2/Q3K1n1 b - -,27,1086,26365,1002897,25397051,934271658 -r1bqkb1r/pppp1ppp/2n1p2n/8/3P4/2N5/PPPQPPPP/R1B1KBNR w KQkq -,29,920,28907,931780,30806903,1010723447 -8/3n4/5k2/8/3P1K1P/N7/8/6Q1 b - -,8,228,2139,56501,543813,14936062 -2b4q/p1r1n1p1/P1pp4/1PP2P1k/1B1P3p/4R2P/R1Q1K3/1N6 w - -,45,1079,47068,1185373,49691453,1291941566 -rnbqkbnr/3ppppp/p1p5/1p6/2P3P1/7B/PP1PPP1P/RNBQK1NR w KQkq -,22,460,11242,266477,7079128,184752782 -8/4Q3/4p3/1kB3bP/2RP4/8/8/1K6 w - -,30,334,11084,115374,4001425,40744172 -bR2N2r/8/3n4/p4B1k/2P1PP1p/3K4/P7/5rq1 w - -,29,1079,26580,1009739,23976222,927220079 -8/2N3r1/8/p1b2P2/P7/2K5/7k/8 w - -,13,376,4470,118139,1377351,34566268 -8/1k6/3K4/6b1/8/3B2p1/8/8 w - -,16,228,3261,46070,645748,9098052 -r2B1qr1/p1n2k1p/1p2p1pn/1bp3b1/4Pp1P/PP3P2/1R1P2B1/2B1K1QR b K -,34,858,30274,837355,30089029,885336217 -rnbqkb1r/p3n1pp/1p1ppp2/2p5/PP1P1P1P/8/2PKP1P1/RNBQ1BNR w kq -,28,805,23568,685987,20923172,622410385 -6k1/8/8/1p3b2/1n6/8/7n/3K4 b - -,25,92,2218,9475,226115,1026261 -8/8/8/3k1b2/8/8/5K2/4n3 b - -,23,133,2709,12275,244644,1163032 -4Bbnr/p1pr1p1p/1p4bq/4k3/1n1pPpp1/3PQPPP/P1P5/RNB2KR1 w - -,28,969,27594,949095,27942741,958169021 -3k1bnr/p4r2/nqp3pQ/P2p3p/1pP1P2P/1P1P1PPB/8/RN3KNR b - -,41,1324,48345,1596634,56173884,1884922755 -rnb1kbnr/p1q1ppp1/8/1ppp3P/5P2/PB2P3/1PPP3P/RNBQK1NR b KQkq -,37,919,33880,910152,33388279,952594979 -5N2/8/2Np4/5q2/2b2k2/K5R1/5n2/8 b - -,41,1030,33916,782830,24771797,544246733 -4rbkr/2n4p/3P2p1/p3p3/2pQ1P1P/P1N1PK2/7R/R1B2BN1 b - -,24,1166,27146,1245357,29338866,1304302205 -2bk4/r3b1rp/p1n2pp1/2PppP1P/Q1p1P3/N5R1/P2P1B2/3R1KN1 b - -,28,1150,32007,1326572,37822679,1572824893 -r1bqkb1r/p1p1pn1p/Qpn5/3pPpp1/N5P1/5P2/PPPP3P/R1B1KBNR b KQkq -,26,917,25009,854886,24406607,830875526 -4kr2/4r2p/7P/ppp5/1Pn1p3/P1b3K1/3R4/N4B1Q b - -,38,1237,43561,1330219,45878370,1387837537 -8/4k3/3N4/2P5/6B1/8/8/1K6 w - -,23,94,2008,8531,175944,903183 -4N3/1B3kBb/4R3/1p2p1P1/1P4R1/p7/8/6K1 w - -,39,388,14502,145341,5292219,58440892 -2k4b/P1P5/2N1p1p1/3r3p/2R4P/1R4B1/8/3Kn3 w - -,6,145,5250,109621,3924816,81910850 -4k3/5n2/1p4B1/r5p1/1K2R3/1Rpp1bP1/7P/6N1 b - -,5,128,3533,92054,2569519,69935807 -B7/k7/4P3/8/8/8/2KQ2P1/6b1 w - -,33,280,9249,89161,2900516,29117721 -3r4/p1p3p1/n3P1kp/Pr4P1/2bbP3/1P3PN1/2K1N2q/2R5 w - -,20,1093,21816,1126348,23615827,1166081373 -2k5/5n2/1pr5/6p1/K3b1P1/2pp4/1R3N1P/8 b - -,29,536,15302,268942,7583459,132091222 -8/1k6/8/p3r3/b7/6K1/8/8 b - -,28,202,5551,27440,739183,3866299 -b7/7K/8/6rk/8/2p3b1/1n6/2r4n b - -,40,54,2324,5306,224867,773979 -1rbQ2n1/8/1N2k1p1/pP1p1p2/Pn3P1P/3p3R/3BP3/2R1KBN1 b - -,17,697,10450,432452,7014579,291519164 -1k1r4/2b5/p7/PppR1pP1/5B2/3K3b/RP6/2r3Q1 w - -,34,938,27225,773540,23379408,676320416 -4r3/R1p5/Pn2P1p1/2r1B3/6k1/1P1N4/1b6/3K3N b - -,38,1011,35305,895695,30405944,766010052 -1k6/8/3r1pP1/p1p5/P1P2B2/1P3p2/N4K2/1Rq3R1 w - -,28,533,11322,264443,6117363,153991213 -rnbqk1n1/pp1pppb1/2p5/6p1/8/1P1P4/P1P1PPPr/RNQ1KBNR w KQq -,27,953,26236,899836,26217818,894708773 -2b2kn1/r7/1n1P1N2/1P3P2/p5p1/PN2K3/1r6/2R1b3 b - -,42,1035,37608,903418,32345185,757320098 -8/8/3K3k/2P5/8/7p/2R5/7b b - -,13,206,2976,51256,740906,13106448 -3r4/3npk2/p2p3r/PBp5/R3b1Pp/2b1P2N/5PP1/2KN2QR w - -,26,1241,33604,1456218,42168845,1705571755 -rnb2k1r/1p1p1ppp/pbp2n2/4p3/P4PP1/1qB1P3/2PPQ2P/RN2KBNR b KQ -,40,1225,47546,1530762,58722822,1950798405 -r1rb4/6k1/8/1p6/2Np1KP1/1RN3B1/8/1r6 b - -,41,1123,44226,1220378,47268334,1309100539 -8/1b6/2k5/8/6pp/2Q5/5r2/1K6 b - -,5,135,2743,56357,1136534,23422397 -1n3k2/BP6/b7/2n1pP2/2pP3P/5pr1/5K2/6R1 b - -,27,524,13114,250786,6213667,121202700 -1n6/rb2B1b1/1P4k1/pP2p3/2P1P1p1/1N3rP1/1R1K2BP/7R b - -,32,1073,33828,1131339,35418100,1183498312 -5N2/1r3k2/B3n3/8/P2P4/1Pp2P1p/K6P/3Q3R b - -,24,716,15410,480289,9736955,311521819 -8/k4r2/4p1p1/p2n3p/PBp4P/2rB1P2/1R4R1/5K2 b - -,32,1027,29630,910218,25269096,762367016 -3k4/8/7P/4P3/8/1N3K2/8/8 b - -,5,80,462,7190,39865,611546 -6n1/2prk2r/P6p/P2p2P1/1n1Pp2P/BP2K2b/B7/1R3qR1 b - -,38,624,22147,408389,14549536,290950479 -1B2B3/1r4k1/1b6/Pp6/4KN1p/8/R7/8 w - -,35,712,23635,489054,15956431,333833195 -rnbq1br1/p2p4/1pp2pkp/1P1Np1p1/3Pn3/P2N3P/2PB4/R3KBQR w KQ -,45,1420,61444,1950811,82955548,2657820636 -8/8/8/3k4/8/8/2b5/4n1K1 w - -,4,80,313,6072,26973,522190 -8/4P3/7k/P3P3/8/3N2K1/8/6N1 b - -,5,115,556,12802,56496,1294882 -r1b1kb1r/3pnppp/2p1p3/pp6/PPN1P1P1/2N5/2PP2P1/R1BQ1BKR b kq -,24,887,21763,816449,20879339,798842525 -8/3k3N/5r2/8/8/1P3P1p/7P/3K4 w - -,10,173,1841,29340,320247,5199333 -rn1qk1nr/pb2ppb1/2pp4/1p4p1/4P3/NPQP4/P1P2PP1/R3KBNR b KQq -,36,1315,45824,1680279,58503218,2146001615 -N7/2B4r/5P1k/5B2/1pP3P1/8/Pp1q4/RKR3b1 w - -,29,1083,26129,941651,23269917,828010907 -1r2kbnr/pb2p1p1/np6/2pP1p1Q/P2PB2P/qP6/N4PP1/R1B2KNR b k -,4,154,4914,186441,6288632,239152935 -r3kb1r/4pppp/2p5/p1p4n/P1Pn1P2/4P3/q2P3P/RNB1KBNR w kq -,20,682,13337,452555,9391479,319674339 -rn1k2r1/3pqQb1/bP1N4/p1p1p1p1/1PPPPP2/B6p/6PP/RN2KB1R b - -,28,1124,28695,1138342,30692433,1209904552 -1r1q1kr1/1bp1p1bp/1p4p1/p2BP3/P1P1N3/1PK1BP2/2n3PP/RN1Q3R w - -,49,1515,67510,2134230,90566926,2920227131 -rq2k2r/p1pp1pbp/b6n/np1Qp1B1/3PP3/6P1/PPP2P1P/RN1K1BNR b kq -,26,1261,31638,1460883,38660861,1716640821 -4k3/r5b1/1q2b2r/1pPpp3/Bp1P2nR/8/4N1P1/5KB1 w - -,22,952,20825,902369,20850061,900833624 -8/p7/PN2k3/K7/3P3p/8/1B2q3/8 b - -,26,268,6593,74202,1766757,21508958 -k7/1r6/8/7K/2P5/8/8/8 w - -,6,96,614,9734,64490,1037711 -4r3/8/3k3P/1K6/8/8/5p2/4N1b1 w - -,11,307,3033,79958,820534,22215694 -3k3r/1R6/7n/2Pp1PN1/8/p2K1Nr1/7P/4b3 b - -,23,620,14379,370725,9442549,239771690 -6R1/5k2/8/r1n4n/1p1p1p1p/1P5P/3Kb3/8 b - -,33,516,15634,219479,6608725,89684111 -2b1kb1r/r4ppp/ppnp1q2/Q1P1pP1P/2P1P3/N7/P2P1K2/R1B2nNR b k -,40,1035,39057,1099873,40117320,1198831515 -2k5/4P3/8/6b1/3p2PP/b2K4/B3N1b1/8 w - -,22,515,10768,253977,5304799,125910634 -1n2r1k1/1b5p/rpP1pb2/p4N2/P1P1pP1p/5n2/1Q2PK2/4RBBR w - -,40,1392,50851,1685283,60350780,1962758786 -rn3k2/p6p/2pb1B2/1r3p2/1P4PP/8/5PR1/K7 w - -,20,493,9812,247596,5138875,133380806 -rnbqkbnr/pp1ppppp/2p5/8/6P1/2P5/PP1PPP1P/RNBQKBNR b KQkq -,21,463,11138,274234,7290026,195464529 -rnb1kb2/p2p3r/7p/1pNppppP/2q5/P7/1PPBPPP1/R1Q1KBNR w Qq -,34,1274,40740,1466876,46463114,1631030464 -8/8/7r/k7/4b1p1/1K6/8/7r w - -,5,205,744,29208,116490,4447280 -8/6P1/1P6/r2b1k2/3p4/3P3K/8/Q1RN4 b - -,28,752,18264,549421,12217070,393399405 -rnb1k1nr/2ppbpp1/1p5p/pQ3q2/NP1p1PP1/4B3/P1P1P2P/2R1KBNR b Kkq -,42,1445,56698,2013697,77748147,2808557989 -r1bqkbnr/p1p1pp2/1p6/1n1p2pp/4PP2/2P4P/PP1N1KPR/R1BQ1BN1 b kq -,34,1246,42156,1484216,51290482,1781216985 -r4bk1/p1qb2p1/1p1pp2r/1Pp1P1Rp/P1K2P1P/6B1/2P1P1B1/RNnQ2N1 w - -,39,1139,41832,1223635,44652580,1318709203 -rn1qkbnr/2p2p1p/pp1p4/4p1p1/4b3/1P3PPP/P1PP4/RNBQKBNR w KQk -,26,830,21925,710209,19554261,642351861 -8/8/8/1P6/1K6/2N4k/8/8 w - -,14,68,895,5679,72938,427709 -8/3n2k1/3P4/1b3P2/p1N1N1p1/P3K3/r1R5/4b3 b - -,27,636,17098,378166,10244357,223066814 -7k/4r3/nP2Nb1P/2R1P3/3K2p1/6P1/4b3/4R3 b - -,25,707,17575,495857,12479749,349479462 -3N4/p2pk1r1/b6p/1n3P1P/1b1p2p1/P5R1/QrP1B1P1/3R1KN1 b - -,30,1157,31837,1170425,33005738,1191209028 -rnbqkbnr/ppppppp1/8/7P/8/8/PPPPPP1P/RNBQKBNR b KQkq -,21,440,10549,242735,6411155,161302508 -r5r1/1kp1qpp1/8/p1pPpP1p/P3P2P/6PB/1PQPKR2/RNB5 b - -,32,994,28982,918323,26024418,841547635 -bb2N2r/8/1q1n4/p4B1k/2P1PP1p/3K4/P7/1Rr5 b - -,47,1008,39763,878850,34796911,779512946 -6N1/r2r4/2p1k2p/P2p2nb/3Pp3/1P2K3/1BB2R1R/8 b - -,26,772,19717,610211,15797542,498417690 -8/4k3/p2R3p/P7/5R2/2Q5/4b3/6K1 b - -,11,587,5481,263528,2493971,113842382 -rn6/p2pq3/1pp1p1pk/4Rp2/P4P2/N4b2/3K1PB1/2BQ2N1 w - -,34,1041,34015,978251,32815241,921063143 -n7/R1p5/P3P1p1/5k2/1r6/1P1NK3/3B1N2/b7 w - -,22,527,12249,275169,6880513,151955678 -2n5/8/6kB/1K4N1/6p1/6PR/r1b5/8 w - -,15,337,5287,131301,2438218,60842140 -3b2R1/2B4n/2r1k1p1/7r/1P3p1P/p1P5/2N5/2R3K1 w - -,30,873,26246,744728,22659788,639633050 -8/2kb2b1/8/7R/8/6N1/2K5/N3b3 b - -,31,720,20661,460963,12877285,282676785 -8/8/5P2/p7/Pb1K2N1/5r2/3k4/8 b - -,23,199,4555,43601,979302,10198627 -k5nr/4r3/4q3/np1P2Pp/1p1P3P/RP1N1N2/6K1/7R w - -,34,1127,31933,1116942,30575238,1067266921 -r2q1bnr/3Qp1k1/5p1p/pp1p1b1P/PpP3p1/N1N2PP1/2RP2B1/2B1K2R w K -,45,1226,52202,1449310,59174712,1672372357 -3B1q2/p6k/P4P2/Bp1pn1p1/3P3p/7P/6R1/4Q1KN w - -,40,999,37150,863523,31662267,720386236 -1r1k1b2/8/p2pQ3/Pnp5/3P4/P2K1Bp1/3B4/R5NR w - -,63,1002,54646,988773,50852692,983001864 -5k2/2R5/1p2B2N/PP6/6K1/2r5/7b/b7 b - -,22,603,14448,379059,9544045,245324803 -2N1R3/5k2/p1K5/p6N/P7/N7/2p5/3n4 b - -,10,238,2779,72398,957516,24774796 -7b/5P2/4Q3/5B2/rp4Pk/8/2R1K3/8 b - -,18,779,15200,663792,13322205,581411720 -2k3B1/4bq2/8/4N2n/8/8/7K/8 w - -,14,442,5883,182221,2492352,78279977 -rnb1kbr1/p1Bp1p1p/1p6/1N1q2p1/2P3P1/1P1PP2n/P6P/R2QK1NR w KQ -,33,1261,40746,1538701,49733366,1868827920 -1r6/8/1k4p1/7p/P3RP1P/2Bp4/6KR/8 w - -,32,455,14535,244363,7680794,128286119 -1r1qbb1r/1Bn3k1/p2p3p/P1p2p1R/3P1p2/P1K3p1/2QB4/R5N1 b - -,33,1351,45140,1802873,61481036,2425801140 -5k2/8/np6/8/3K4/5p2/3b4/6n1 b - -,22,113,2499,13156,292848,1513657 -2K5/R3B3/5q2/8/P3b3/8/6k1/8 w - -,18,748,12514,453171,7883016,266561008 -7R/8/PP4P1/8/3p1k2/1r1P1b2/8/3N2K1 w - -,24,531,11722,249873,5357665,112129918 -1N6/6k1/8/2r3P1/4B3/8/K1R5/3bN3 b - -,21,626,13399,387975,8292914,236761540 -7R/p7/1kB1P2Q/3q4/1P3bp1/8/2KR2P1/8 b - -,37,1215,37707,1370480,38577528,1467360500 -r1b2knr/ppqp2bp/1N3pp1/2p1p3/6P1/3nPP1P/PPPPK3/R1BQ1BNR b - -,29,592,17133,364171,10979619,246628771 -6n1/4k3/2P3P1/8/7N/p4r2/1r6/4b2K w - -,6,207,1628,52222,497487,15384588 -8/8/K7/1P6/8/8/4N1k1/8 w - -,11,72,820,3933,45147,260251 -r3kb1r/p4ppp/3p1n2/1pp3P1/P2pP3/R6b/1PK4P/1NBQ1qNR w kq -,35,1436,42957,1743727,52597845,2106531575 -5k2/8/b7/1r1n1pP1/1p1p3p/1P5P/K7/2R2n2 b - -,25,377,9287,124822,3182760,42842692 -6n1/2k1N3/6P1/b7/8/p3r3/7N/6K1 w - -,13,333,4238,112618,1475389,39663776 -1n2kb1r/1q2p1p1/rpbp4/p1p3Np/P1PP1pn1/1P2PNPB/3B1P2/R2K3R w k -,35,1196,40302,1379748,47959756,1652043039 -rn5r/ppp2k2/1B3n2/3qp1pp/Pb3p2/1P1P3b/R2QPPP1/1N2KBNR w K -,27,1630,45668,2552421,75207612,3955150683 -rqbk1r2/pp1p1p2/3P4/2pN1PNp/4p1Pn/Q6P/PP2PKB1/R3B2R w - -,47,778,34220,649338,28353696,593869569 -b7/b3r3/1k5N/7P/P3p3/8/2K5/8 w - -,12,225,2666,56318,664467,15150008 -2k1K3/8/1r6/8/3P4/P7/6R1/6N1 b - -,17,336,5082,96479,1474480,28306669 -1r6/2k4p/7P/8/3R1b2/8/1p6/7K w - -,14,351,5000,125315,1813580,46334074 -1krr4/n6P/p4B2/P7/1P2B2P/1Pp5/7K/2N5 b - -,19,603,13338,402631,9278330,268499112 -2Bn2k1/5b2/7r/pP3p2/P4pP1/2R1PR2/5K2/2b5 w - -,27,920,23873,732044,19330953,571513872 -3qkbnr/r1p2p2/p1np3p/1p2p3/1P5p/P4PPB/2bPK2R/RNBQ2N1 w k -,26,897,23484,797343,22397666,758906823 -7K/8/3r3P/8/3n3k/2p5/8/7r b - -,33,120,4210,15724,557893,2822311 -2n5/8/6kB/1K6/r5p1/1b1N2PR/8/8 b - -,29,533,13761,270332,6914531,144988744 -6r1/k1n2B2/8/p3p3/6p1/2N5/1b2K2B/3r4 b - -,42,919,32472,692709,23595782,500198461 -8/r5N1/8/p4P2/Pb6/3K4/6k1/8 b - -,24,229,5332,52958,1215278,12445888 -6Q1/3k4/3n4/1P1P4/2RP3P/8/4K3/1N6 b - -,9,337,2399,83462,588411,20549300 -1n6/4Nnkp/2bb4/2p2r2/P1PpP3/1pBP3K/8/4R3 b - -,38,933,31217,741819,24509561,567863365 -1n2k3/2q2N2/2rPK3/5P1p/1P6/8/2R5/4b3 b - -,27,446,13491,223018,7034287,116187625 -1r5k/5b2/1p4RP/1Pnp4/6pB/3p3K/1p6/5B2 w - -,5,128,3077,75121,1764192,45010563 -6k1/8/6KP/1B6/3n4/8/8/7R b - -,10,236,2072,45578,361721,8274586 -r1b1kbnr/pp1ppp1p/1qp3p1/2n1P3/3P1PP1/P4N1B/1PPQ3P/RNB1K2R w KQk -,33,978,31632,970176,31872285,1003910551 -k7/8/8/4K3/2p5/2P4r/1N6/8 b - -,15,156,2492,25275,411735,4318568 -r1Nn3r/1bpk2pp/6P1/pP3p2/1b1pp1nP/BP3PqR/2PPP1B1/1Q2RKN1 w - -,28,1345,33864,1604160,42047385,1957350889 -q2k1r2/1pN2p1p/3ppn1b/P5pP/P1p2nB1/3P4/2Q1P3/R1B1K1NR b K -,33,1215,38892,1483469,47513088,1857440549 -rnbqkbnr/pppppp1p/6p1/8/8/2N2P2/PPPPP1PP/R1BQKBNR b KQkq -,21,441,10235,235576,5926162,146261834 -4qb2/4pk1b/rpp2npr/p2P3p/4NPPP/1Q1P3R/PP2N1B1/R1B1K3 b - -,24,1043,25513,1093359,29230114,1243106969 -8/7k/np6/8/8/5p2/1K6/6n1 b - -,13,99,1439,7463,117430,655766 -r1b1kb1r/ppnpp1pp/2p2p1Q/8/1q1PPP2/4B3/2P1B1PP/RN1K2NR w q -,40,1327,48676,1587760,59326622,1920417044 -rn2kbnr/p3q1p1/2ppbp1p/Pp2p3/4PB2/1P1P2PP/R1PN1P2/Q3KBNR b Kkq -,29,929,27001,895205,26497056,897608781 -8/8/4b1P1/7P/8/3k4/8/3K4 w - -,4,66,359,5458,42728,620333 -5k2/8/1P1r2P1/pR6/8/K7/6B1/8 b - -,17,406,6570,152843,2429455,56585463 -1n2rk2/r2b4/1p5p/p2RpN2/P1P1pP1p/8/4P1B1/b3K1nR w - -,33,977,28794,907124,26154409,850420925 -4Bn2/7k/6p1/b3p2p/7P/3r4/8/5K2 w - -,10,265,2830,74404,828075,21660411 -k7/8/p1b5/Pr6/1R6/8/3p1B2/3K4 w - -,23,504,10657,233630,4719602,105082605 -3r4/1k6/8/8/3PK3/P1N4R/8/8 b - -,19,453,7405,173125,2768419,63242987 -rnb1kbnr/pp2q1p1/2pp1p1p/4p3/P4B2/1P1P2P1/R1P1PP1P/1N1QKBNR w Kkq -,30,836,25672,738264,23051133,687830205 -1r4r1/1bNB4/p1p2Bkp/2b5/1PR1P3/3p4/P7/3K2N1 w - -,40,1116,42331,1157445,42172866,1148838431 -8/k1b5/8/1K6/B3p3/2N3p1/2r5/8 w - -,12,262,3095,66836,961312,21202282 -8/8/4b3/4k3/1p1pB3/8/7K/8 w - -,17,284,3835,60566,784800,12170166 -1K2b3/2R5/P7/8/8/8/8/7k b - -,10,176,1845,31913,351653,6117025 -3k4/7p/2b4P/3pb3/p1p5/4rRp1/2BK4/7r b - -,45,757,30470,517849,19874842,342598066 -8/6k1/3rBr2/Pp6/3N3Q/1p6/1b4K1/8 b - -,26,908,20960,712596,17843574,587890984 -r1b1kb1r/p1npp2p/2p2p2/R3N2p/1p1PPP2/4B3/K1P1B1PP/7R b q -,21,934,20889,890255,21175515,873641300 -bb1N4/8/1k6/7P/P3p3/3r4/5K2/8 w - -,11,305,3171,83660,877653,22708437 -8/1k2Br2/p3b3/PpQ5/1P6/3p4/8/R1K5 b - -,22,642,11918,360926,7046881,213938430 -5R2/4k3/1B6/5P2/8/4r2p/N7/3R1K2 b - -,13,384,4739,142200,1883846,57025153 -2b5/6r1/rp1k2N1/p3bpR1/PpPpP3/RQ1B3P/3P4/1N2K2q w - -,4,144,3583,124471,3308688,116245804 -8/5Pr1/7k/2P5/1p2R1P1/4K3/7b/qB6 w - -,22,590,12657,364760,8163679,241661568 -4k3/8/8/2K1PR2/1N5P/2p2p2/4r3/8 w - -,22,332,6989,100961,2132496,31839335 -4n3/k7/8/p3pN1p/2B3r1/5K2/1b5B/1N1r4 w - -,29,1152,28200,1050741,25099001,899712133 -1k6/1p2B2p/3pp3/4QpRP/2pPn3/1R2b3/8/K6B w - -,44,967,40497,839781,34946278,689195319 -r1k4r/5pQ1/p2p3b/Ppp2pP1/3R4/n6b/1P1K3P/2B2R2 b - -,26,834,21420,697950,18417679,603573615 -5bnr/1pq2k2/8/4p1pp/ppN1BPP1/B1P1p2P/P2PK2R/5RN1 b - -,36,1607,52457,2169874,72191075,2823541187 -6k1/8/4P3/P3P3/8/8/N5K1/6N1 w - -,15,60,936,4229,70338,317437 -2bqkbnr/rppppppp/n7/p7/2P5/PP6/3PPPPP/RNBQKBNR w KQk -,19,398,8820,204573,5072498,129375227 -8/1BNk2P1/8/1P6/8/pb6/4KB2/6R1 b - -,14,542,6808,256959,3228897,120155987 -8/2p5/1p4P1/rp3p1p/1k2bP2/1N2n2K/8/8 w - -,10,311,2966,82278,841528,23129482 -r1b2q1r/pp1Pbk1p/n3p1pn/2p2p2/6P1/PP2PP2/1R1PQ2P/2B1KBNR b K -,27,840,23950,770026,23033167,764848090 -8/k7/8/8/B3Kb2/2N3p1/3r4/8 b - -,27,426,10355,170989,4075960,67845249 -5b1r/8/pp1p1k1p/1P2n1pP/P1bP1np1/1R1BK3/2P2R1N/2Q5 w - -,38,937,33589,896565,30839457,853069613 -rnbqkb1r/pp1pppp1/2p4n/6Pp/8/3PB2P/PPP1PP2/RN1QKBNR b KQkq -,22,588,14288,390995,10371588,291448301 -2k5/8/8/1q5n/2B4b/8/5N1K/8 w - -,20,652,10772,354795,5488694,182724583 -n4kn1/1r1B4/5pr1/1P1Pp3/3B1P1P/2pP3q/2Q5/1NR1K2R b K -,37,1282,46504,1615546,58417154,2045146904 -r1b2kn1/1p2q2r/p2p4/1N3pN1/PbP1p2p/3PPP1Q/1P1B2PP/1R1K1B1R b - -,35,1219,41618,1452909,50943852,1794077277 -2k5/4P3/8/2bb2b1/3p2PP/3K4/4N3/1B6 b - -,31,449,11755,187665,4839227,84436997 -1r6/8/R4P1k/2p2P2/7P/1b4Pp/7K/r1R5 b - -,30,765,22465,529164,15303046,352305478 -1k3b2/8/1pR1R3/pP2pp2/B7/6r1/P6K/1n1N4 b - -,29,674,15769,399940,9126750,241398563 -2b5/bN1k3r/7p/2P4P/4p3/PnB5/R2P3N/5K2 b - -,20,466,10134,236670,5573110,131934763 -6k1/N7/p1Kn4/p6r/P7/8/8/3N4 w - -,10,253,3040,70294,885743,19607920 -4n3/5B1k/5R1p/pp1p2pP/3P2p1/6N1/2P2KQ1/R7 w - -,46,353,15393,128055,5351575,47760417 -8/2p5/rp4P1/1pk2pNp/5P2/4n3/3N1K2/1b6 b - -,26,461,10227,166524,3861964,61453132 -8/8/1n1k4/Rp4r1/6p1/2K5/r7/8 w - -,11,364,4337,132802,1711050,50739295 -8/6k1/8/1n1P3p/4K3/1P5p/3R4/8 w - -,18,272,4538,61134,1049869,13579691 -1rb1kb1r/pp1ppp1p/2p3pn/q1nPP3/5PP1/P6B/1PPQ3P/RNB1NK1R w k -,31,981,29802,968066,30246986,1002430565 -8/1R6/3r1k2/2K2P2/7p/p5b1/8/8 b - -,21,330,7686,113023,2707566,41072402 -2N4R/1K6/p3k3/p7/P5N1/N7/3n4/7r b - -,24,687,13443,383097,7279257,206261446 -8/k7/8/8/8/3K1QbQ/8/5B2 w - -,43,433,18735,179368,8040054,76429599 -1r6/3k1N2/1p3R2/1P3p1K/P7/4p3/1bB5/8 b - -,21,478,9290,217800,4329115,103089396 -rn4r1/p2k3p/2pb4/rB2Bp2/7P/8/1P3PPR/2K3R1 w - -,32,1123,34713,1175271,36030065,1196467649 -8/1Pk5/1N3B2/2P2p1p/8/8/1r6/7K w - -,22,290,5510,78545,1476832,21701294 -2kq4/4Q3/1n1p3b/r1NP1bpp/pPP2PP1/p3P2P/4K3/2R1NBR1 b - -,33,1452,43353,1829511,55661262,2275321404 -rnq3nr/3k2Bp/1p2p1p1/8/P5P1/2Q4P/3bPKb1/3r1RNR w - -,38,1574,52246,2226215,72963887,3151185804 -2r1kb1r/p3pbpp/n4p1n/1pp1N3/Q3p1PP/2PP4/PB6/RN2KBR1 w Qk -,37,1064,38893,1092902,39842401,1111165380 -r1bnkbr1/p1p2ppp/7n/1p4q1/P2pp1PP/1PN2P1R/1BPPPK2/R2Q1BN1 w q -,30,1346,38069,1631657,47004887,1960693269 -8/B1R5/7P/1Q6/3P4/k7/1b6/1K6 b - -,4,168,1078,41724,326024,12736109 -8/3Pk3/p7/P7/N1p1p1B1/6Q1/7R/5K2 b - -,6,295,1578,72366,385729,17035221 -8/8/1B3N2/5k2/5P2/R2r2pp/5R2/5K2 w - -,36,613,18703,317823,9538390,160765823 -6r1/8/8/1p1n4/3k2p1/1K6/8/2R3r1 w - -,17,477,6935,203343,2882448,85766865 -3N3k/Bn5P/7B/7R/3K2p1/2rb2P1/8/8 b - -,25,675,15680,403066,9068683,233688217 -8/1n6/8/4k2p/7P/8/3K4/1R6 w - -,21,222,4070,41364,743974,7745150 -3N4/7k/7B/P3P2P/bp1p2P1/3KP3/8/8 b - -,12,184,2125,33522,392235,6387732 -rnbqkbnr/p1p1p1pp/1p1p1p2/8/7P/N1P5/PP1PPPP1/R1BQKBNR w KQkq -,24,624,16458,421449,12057698,313684316 -1nbq1k2/3ppp1r/6p1/1pp4p/Pp3P2/B2PP1PP/1b4B1/RN1K2NR b - -,35,916,31428,854386,29175123,821759882 -4k1r1/8/2N5/2B2np1/ppp2P2/4p1P1/Kb4b1/R4BR1 w - -,30,1035,30320,999451,29912743,963319076 -r2qkbnr/2p2p2/p1np3p/1p2p3/1P2b2p/5PPB/P1PPK2R/RNBQ2N1 b k -,34,932,31085,877025,29720192,867358010 -5r2/1pk2p1p/3ppn1b/q5BP/P1p3B1/3P1n2/1Q2P3/R2K2NR w - -,42,1969,74651,3235617,120465860,4966745183 -k4N2/r7/2P4n/1p1PK1Rp/1p5P/1P4q1/8/7R w - -,5,166,3408,104381,2179488,64036975 -1n1b2K1/8/1k2P3/2p1n3/2Pp4/3b4/8/8 w - -,4,117,646,17170,123856,3104023 -k7/Pq6/2n4p/3p4/7B/1b1p4/6K1/5nN1 b - -,34,487,16640,231820,7989179,115630952 -2b5/7r/rp1b2N1/p1k2pq1/PpPpP3/1Q3P1P/3PK3/RN3B1R b - -,44,1234,49323,1339193,51726362,1404437765 -1nb1qbn1/4rk1r/ppNp3p/5ppP/P5P1/1P3P2/2PPP1RN/1R1QKB2 b - -,29,714,20587,501386,15472121,386067072 -r2qkb1r/p1pp1p1p/b1n4n/1p2p1B1/2QP4/6P1/PPP1PP1P/RN2KBNR b KQkq -,32,1307,40411,1613865,50740758,1991390841 -br1qkbr1/2p1p2p/1p4p1/p2pPBN1/P1Pnn3/4BP2/1P1K2PP/RN1Q3R w - -,6,191,8093,248065,10392067,323779715 -8/8/k2b4/2R5/N5PP/2K5/8/5b2 b - -,17,330,5564,110536,1917159,39056971 -1rbqk1nr/p2p3p/n6b/p1pPpP2/P5p1/2P5/1P2PP1P/RNB1KBNR b KQk -,32,759,24740,599525,19905290,492337571 -r1b2kn1/Np5r/p2pq3/8/PbP1Np1p/3PPP1Q/1P1B2PP/1R2KB1R b - -,42,1332,52820,1726082,66612195,2240881035 -3rkbnr/pb2ppp1/np6/2pP4/P2PB3/4q3/NP3PPP/R1BQ1KNR b k -,48,1605,74256,2543269,113989728,4022133960 -r3k1n1/p2p2p1/1p4N1/2r2pq1/2b2PPp/b1p5/P3PB1P/RQ1K1B1R b q -,44,1294,54944,1655001,69355325,2151191277 -r1b2kn1/Np5r/p2p1q2/8/PbP1Np1p/3PPP1Q/1P1B2PP/3RKB1R w - -,33,1396,46515,1841227,62475830,2407497315 -2b2kn1/8/1n1P1N2/1Pr2P2/p5p1/PNR1K3/1r6/4b3 w - -,24,836,17139,604727,12541540,443971804 -5b1r/1k6/1pR1R3/pP2pp2/B7/3N2K1/P7/1n6 b - -,23,627,14318,402693,9305310,268373666 -bn5r/3k3p/R2q4/p1Pp4/P7/3p4/3P3n/1NB4K b - -,35,485,14678,213237,6733548,104700620 -2bkq3/4p3/nrpp1nQb/3P2pp/pBP3P1/PP2P2P/3NKP1R/R4BN1 w - -,42,1463,57483,1957673,75078346,2542445133 -r1b2b1r/ppN3kp/2n1p1pn/2p2p2/P4B1P/2PP4/4PPP1/2RQKBNR b K -,25,847,19574,675018,16513580,582450742 -r3k1r1/1bp1p2p/1p2Bbp1/p1P1P3/P3NB2/1PN2P1P/3K2P1/R3Q2R b - -,26,1364,32117,1637698,38133256,1897901918 -1N1k4/6b1/P3p1p1/1b1Prr1p/2PB3P/8/3KR2R/n7 w - -,32,891,24920,728337,20340841,611553517 -1k3b2/4Q3/4b3/2p3NP/2Bp4/P1P3P1/2N1KP2/3r3R b - -,25,971,20619,828232,17488343,704451685 -8/1N6/3p1P1R/1b6/5kn1/K7/7p/7n w - -,16,370,6900,151261,2983491,64950761 -1r1qkb1r/2p4b/p2p3p/P2npp2/3P1P2/P4Qp1/6BR/R1B1K1N1 w k -,35,1239,45519,1599925,59783885,2101316758 -4N3/1B2k1B1/7R/1p2p1r1/1P2QP2/p5R1/8/1b4K1 w - -,54,802,39403,629469,30596406,516063860 -3n4/1B5k/4p1b1/1p2P2p/p6P/Q3P3/3K4/2N5 b - -,15,431,6497,185174,2813847,79794297 -rnbqkbnr/pppp1ppp/4p3/8/3P4/7P/PPP1PPP1/RNBQKBNR b KQkq -,30,783,23856,654281,20362581,588595079 -5b2/6P1/p6p/P3k2P/6R1/1b1p2P1/3R4/4K3 w - -,28,474,13304,207961,5786723,90259154 -5b2/6k1/8/3QP2p/PN2P2P/3N4/6K1/8 w - -,36,282,9708,96430,3233593,32199305 -2N5/7k/N2p4/1p3nPr/P1PP3p/1P2QP2/7P/2K2B1R b - -,17,658,10350,395273,6333423,240426151 -5bnr/p2kq1p1/nrppb3/P5Qp/1p2P2P/1P1P1PP1/R1P5/1N2KBNR b K -,29,1166,36087,1368127,44315729,1620659368 -6k1/8/2B5/P3P3/8/5N2/8/2N2K2 b - -,5,130,632,16503,80230,2077838 -6b1/r1k5/np5N/6Q1/P2PPPPp/1P6/b4B1K/3BR3 b - -,21,794,16130,601367,12744069,474131323 -6R1/6p1/4q2n/4k3/2K1b3/8/8/8 w - -,4,172,1781,67908,837445,30369993 -7r/8/2np1npb/pRp4k/P1p1br2/5P2/3K2BP/8 b - -,39,725,27426,493795,18724919,330066228 -r1bqkb1r/pppppp1p/2n3pn/8/2P5/8/PP1PPPPP/RNBQKBNR w KQkq -,22,484,11882,294303,7825994,211609907 -7k/8/4P3/8/7B/5p2/3K4/8 w - -,15,57,825,4785,70858,471209 -rnbqkbnr/pp2p1p1/2p5/3p1p1p/1PP5/7N/PB1PPPPP/RN1QKB1R b KQkq -,28,833,24569,743804,22819719,711808669 -BN6/6B1/3k4/p7/1p1K2Pp/P7/1P2P3/R7 w - -,33,218,7565,51094,1816207,12533615 -8/b4B1N/P5Pk/3p4/8/2R4P/4p3/2K1N3 w - -,29,305,8242,97804,2677031,33879586 -rnbqkb1r/2p1pppp/5n2/pp1p2B1/2PP4/7P/PP2PPP1/RN1QKBNR w KQk -,33,1051,34833,1100571,36975122,1195267340 -8/1k6/1r5b/8/4K1B1/6p1/8/1N6 w - -,18,430,6623,162282,2517811,62078375 -r4qnr/p1p1kp2/1b4pp/Qp1p2P1/PnPP3P/1B2P2b/1P3P1R/R1BNK3 w Q -,26,1008,26947,1007776,28582004,1048259996 -2b1qb2/3kp3/nrpp1n2/3P1ppp/pBP3P1/PP1QP2P/3NKP1R/1R3BN1 w - -,32,913,30583,914591,31569084,978450277 -r3kb1r/pbnpp2p/2p2p1p/Rp6/3PPP2/4B3/2P1B1PP/1K4NR b q -,22,732,16515,551317,13055868,437252213 -4q3/r3bk1b/1pp1pnpr/p2P3p/P4PPP/1QNP2NR/1P3KB1/R1B5 w - -,44,1502,61285,2110391,86440647,2979560445 -k2B4/Pq6/2n4p/3p4/b7/3p4/6K1/5nN1 w - -,15,524,7491,256412,3744208,127664925 -r4bnr/p1n1pkpp/1p1P2b1/2P5/Q2p1P1P/P2P4/1N2P2R/R1B1KBN1 b - -,26,992,25068,946787,24716344,936186032 -6b1/2r3Q1/np1k3N/4P3/P2P1PP1/1P5K/b4B2/3BR3 b - -,3,109,2052,73503,1409612,51004491 -1n2rk2/8/rpbRp2p/p4N2/P1P1pP1p/8/4PKB1/b5nR w - -,30,877,24802,734280,21051854,635309816 -8/p2n3k/P4P2/1pqp2p1/3P3p/2BN3P/3Q2R1/6K1 b - -,23,761,17914,607248,13989765,478527768 -b7/n1k2N2/P7/2p3b1/2PpP3/3P2K1/1p5n/8 w - -,11,307,3083,82862,824887,22212861 -6nr/1k1r4/2n5/Pp1p3p/1p1PP1PP/1P3N2/7q/R1N1K2R b - -,44,857,33689,688345,26236907,562422164 -r4bkr/1b2p3/1Nn2pp1/pPpP4/1P3P1p/P3PN1Q/R5Pn/2B1K2R b - -,33,1424,45277,1897192,59764912,2456652899 -8/8/7r/k7/3Kb1p1/8/8/1r6 b - -,46,250,10220,40565,1568042,7250995 -2r1k1Br/2p4p/4pbp1/ppP1P3/P4B2/1PNRQP1P/4K1P1/6R1 b - -,18,778,13766,599779,10957687,480515393 -7r/r4b2/2B2k1p/P1pp2n1/1B1P1K1R/1P2p3/5R2/8 w - -,32,972,29050,889851,26589476,815012788 -8/4P3/6k1/P3P3/8/3N4/6K1/6N1 w - -,23,153,3487,16754,376161,1733768 -8/1k1N4/4R3/1Kn3p1/8/2pp4/7P/8 b - -,13,318,3912,88577,1111098,24275087 -8/k7/7P/Pb6/3N1b2/r7/4pK2/8 b - -,37,429,13150,147301,4692371,51227930 -5k2/8/2r1Br2/Pp6/3N4/1p4Q1/1b4K1/8 w - -,42,1060,38041,996194,34009949,911735431 -1n6/1P4k1/bB6/4nPr1/2p4P/4Kp2/8/R7 w - -,26,637,15089,371457,8594293,215345013 -6r1/1p2pkbp/3p3n/4RPp1/2P1p1b1/6P1/3K1N1P/B4B1R b - -,27,751,20367,581380,16234080,478433270 -8/7B/k7/1p5R/2P5/5Np1/8/2K5 b - -,7,230,1701,51435,418157,12139825 -rnb1kbr1/ppp1qp1p/3pp1pn/8/1P3PP1/B6N/P1PPPK1P/RN1Q1B1R w q -,24,644,15602,440761,11421682,336860851 -rnbqkb1r/ppppp2p/5p1n/6p1/1P4P1/2N1PN1P/P1PP1P2/R1BQKB1R w KQkq -,32,633,20517,447156,14730460,348530907 -b3k1r1/8/1B2n3/1pn1r1p1/p1p2P1N/b3p1P1/5N2/RK3BR1 w - -,30,1167,35125,1381459,42917733,1694767072 -6r1/rkp5/5pP1/p2P1P2/P1P1P1q1/1P3p2/N1K5/1RB3R1 b - -,30,786,23316,634585,19050830,530980198 -r1b1kbnr/pp1p1ppp/n1p2q2/4p3/4PP2/P7/1PPPB1PP/RNBQ1KNR b kq -,34,868,29629,803782,27627724,786614245 -3kr3/6R1/2P4n/3p1PN1/1b6/6P1/3N4/2nK4 w - -,26,613,15078,355322,8530768,204365759 -4r3/8/7N/p4p2/P4P2/4bk2/8/1K6 b - -,26,207,5561,50270,1250948,11696358 -8/k7/4P3/8/2Q2bB1/8/1K4P1/8 w - -,35,428,13479,143145,4522908,47164860 -8/8/1k1P4/1p2n1K1/1p5P/1PNR1R2/8/r7 b - -,29,799,18950,532307,11556783,328323708 -2b4k/1r6/2Pp1r2/p1N2p2/P4PPp/1P5P/NQ1K1n2/R5n1 w - -,33,920,28170,791245,24359709,693662611 -8/1k6/8/4qPpp/r6P/7K/8/R3B3 b - -,49,673,25933,447647,15810724,291423880 -1n1rkb2/1q1b4/2Npp2r/1pp5/2n1P2p/PPPP4/4N1P1/1RBB1K1R w - -,36,1128,36638,1187713,38885470,1296943575 -2b1k3/4p1rp/1r1nP3/p5p1/Pp3nP1/1QNP1P2/7P/4KR1R b - -,31,745,22846,577478,17427901,464514047 -8/5k2/p2p1n2/P2P2Q1/P1p5/2N2KB1/4B2R/6b1 b - -,18,741,10358,419910,5860712,238238301 -rn1kr3/1b1p3p/2p3q1/p1b5/PP2Q1n1/2Np3n/1R1P3R/2B4K w - -,36,1724,55830,2622716,82638001,3805966744 -5k2/2B2b2/7P/P3P3/2K3P1/8/8/8 w - -,7,80,1121,11882,174117,1908381 -6k1/8/1P6/p4BP1/r7/2R3b1/1K6/8 w - -,30,611,15867,322882,8064066,166601704 -r6b/2P2P2/8/5Bk1/1p4P1/8/4K3/6R1 w - -,34,821,25769,578838,18367740,397281014 -5k2/8/8/1K2P3/1N2R2P/2p2p2/5r2/8 b - -,14,298,4556,98227,1555078,33465073 -8/4NP2/3p4/1b3q2/5kn1/6R1/K7/8 b - -,36,754,21833,469441,13624676,297058612 -2r5/3K4/6pP/5nk1/8/2p2p2/8/8 b - -,27,102,2446,14138,330417,2349813 -rnbqkbnr/1p1ppp1p/p5p1/2p5/1P3P2/P7/2PPP1PP/RNBQKBNR w KQkq -,20,457,10419,262228,6606668,180170663 -2Q5/p6k/P7/2P5/r2R4/1P3r2/7K/8 b - -,24,720,13699,402362,7637562,222705512 -4k1n1/8/2Nb4/5P2/p1K3p1/P5N1/6R1/1r6 b - -,30,735,20149,489926,12882581,308977493 -rnbqkb1r/ppp4p/5n2/3pp1p1/P1P2p2/R2P3P/1P2PPP1/1NBQKBNR w Kkq -,27,1077,29576,1166930,33211447,1308304348 -rn4r1/p2kp2p/2pB4/1B2Np2/r2b3P/7R/1P2KPP1/6R1 b - -,6,276,10196,434053,15673121,630832585 -2q1k2r/1p3p1p/3ppn1b/rN1n2pB/PPp5/3P4/1BQ1P2P/R3K1NR b Kk -,38,1541,55154,2183493,78961847,3095914585 -5N2/8/1r2nk2/8/P2P4/KPp2P1p/7P/4QB1R b - -,22,670,11997,365398,6539301,203699433 -4qbn1/4pk1b/rpp2Ppr/p2P3p/5PPP/1Q1P3R/PP2N1B1/RNB1K3 w - -,40,725,29044,641271,25744198,632826919 -8/P7/8/2p1R1N1/2P5/6K1/8/2k2q2 w - -,23,448,7792,166691,3387617,72547247 -k7/3K4/8/6n1/6p1/8/7r/8 w - -,7,163,801,17800,93543,2076111 -1b2b3/8/8/3k3P/3Q4/r7/4p1K1/8 b - -,3,66,1720,35998,942198,19789311 -3k1r2/1pN2p1p/3ppn1b/q5pP/P1p3Bn/3P4/1Q2P3/R1BK2NR b - -,40,1542,55253,2151718,74949184,2934368590 -r1bqkbn1/pppppppr/2n5/7p/5B2/3P4/PPP1PPPP/RN1QKBNR w KQq -,31,713,21989,552748,16979183,461067687 -rnbqk3/1p3ppr/2p1pb1n/p2p3p/1P6/P2P3P/2P1PP2/RNBQKBNR w KQq -,25,862,21555,766788,19975850,724308919 -6R1/3k1r2/2N1r3/1P1n2p1/8/K7/6p1/8 w - -,23,763,15176,498458,9562680,315950613 -3k3r/1r2b2p/p7/npp1p1PP/2PpQ1b1/PN3K2/RP2B3/6N1 w - -,5,138,5004,140614,5032489,145420340 -2N3n1/8/4P3/P7/2k3P1/7p/6b1/1K4R1 b - -,20,343,6011,112447,1970498,38915212 -8/8/n3kP1p/1p6/6pP/8/2rR2K1/r7 w - -,8,226,2593,70726,1018178,27583092 -1rb3rk/1p6/n7/Bqbpp1p1/P1p3Qp/5NPK/2P3nP/RN3R2 w - -,33,1384,43908,1804816,58331759,2364462572 -6k1/8/4P3/8/7B/2K2p2/8/8 b - -,5,79,442,6972,48272,736540 -3k4/8/8/1NP5/6B1/8/8/K7 b - -,2,38,176,3339,16281,310017 -8/3b4/1k4P1/2R5/8/1Nb3N1/8/2K1b3 w - -,26,612,14329,342882,8123564,196882807 -r1b1kb2/3pp1rp/1qp2ppn/pp2n3/2PPP3/NP3Q2/P3NPPP/R1B1KB1R w KQq -,36,1252,43800,1492591,53067526,1806973447 -3r3r/8/2k5/8/3K2p1/8/8/8 w - -,5,154,689,21442,119762,3776514 -b4brn/2k5/P1pr3R/2B2Pp1/p1PppQP1/N5P1/R2PB3/1N3K2 b - -,15,569,9885,376987,7387789,284958572 -8/5Bk1/4P2R/5PK1/1p3B2/8/8/2n5 w - -,27,146,3961,25013,676055,4944781 -8/8/PP4P1/4k3/3p1N1R/3P1b2/5N2/r5K1 w - -,2,48,999,21185,468505,9493508 -8/7n/P1k3n1/5P2/1p3R2/1B5P/3R4/1K4N1 w - -,43,522,20593,258824,9686849,129754852 -8/8/1k2N3/1p2P2q/1p1p4/3K4/3nB3/8 b - -,28,358,9704,130810,3452986,48704687 -r3kb1r/1p2pppp/8/p1pQ3n/P1Pn1P2/4P3/1q1P3P/RNB1KBNR b kq -,38,1248,41799,1369674,45587278,1493352509 -1r2kbnr/p3qbp1/n1pp1p2/P6p/Rp2P2P/1P1P1PP1/2P5/QN2KBNR b K -,30,882,27947,842800,27618388,851795296 -1rbk2nr/pp1pbppp/n1pq4/4p3/P1B1PP2/2P4P/1P1P2P1/RNBQ1KNR w - -,35,1175,39028,1323568,43314736,1486333015 -rn1q1b1r/p1p1pppp/1pk2n2/3p4/4PPbP/6P1/PPPP2B1/RNBQK1NR w KQ -,27,936,27032,891122,26790225,864434025 -1R6/Q7/5kp1/pp1p1p2/P4P2/R2KB1P1/4q1P1/4b3 w - -,2,33,999,14103,439860,6615104 -r1bqkb1r/p1pp1ppp/1p3n2/6B1/Pn1p2P1/7B/RPP1PP1P/1N1QK1NR w Kkq -,29,905,26302,843889,25851545,855326188 -1b2Q3/1k6/8/8/5Q2/3K4/6P1/5B2 w - -,55,444,21708,172814,7994613,72134860 -8/p7/P6B/4k3/K6p/8/8/8 b - -,8,96,724,9488,69931,948292 -6nr/2p1kp2/pr3qpp/1p1p2P1/PnPP3P/1P2P3/B4P1R/R1BNKb2 w - -,23,871,19147,729025,16476562,633021776 -8/1B3n1n/8/P2p1P1p/1p6/1k5P/2Rb1R2/1K4N1 w - -,28,480,13845,239810,7095053,126271899 -rnb1k1r1/3pqpb1/1P2p1Q1/p1p2Np1/1P1P1P2/B3P2p/2PK2PP/RN3B1R w q -,43,1295,55687,1689056,72307741,2231886931 -rB5r/pp4k1/5n2/q3p2p/Pb3pp1/1P1P3N/R2QPPP1/1N2KB1R w K -,23,1010,25041,1067873,28954450,1216784742 -8/7k/8/8/6Pb/3p1KB1/r2N4/8 b - -,20,378,8535,148900,3412147,60154608 -1rb1kb1r/1p1p2Qp/p1p2n2/qB2p3/3P1p1P/1PP1PP2/P2K2P1/RN4NR b k -,34,1219,35707,1259538,36653521,1273601051 -rnbqkbnr/p1p1p1pp/1p6/3p1p2/PP4P1/7P/2PPPP2/RNBQKBNR b KQkq -,27,591,16555,402435,11802075,310323955 -5kr1/4q1nb/1pB1p1p1/4B2P/p4P1P/N2RQ3/1P1N4/5K1R b - -,22,1239,25952,1385459,30926557,1607785618 -6n1/8/P7/1k6/1pR4n/1B5P/5K1R/6N1 b - -,10,276,3249,96421,1219604,36909611 -1k6/4b3/6P1/7n/8/2q5/5N2/7K w - -,9,382,3394,129047,1173362,42672768 -rnb1kbr1/p1pp1p1p/1p2pq2/6p1/2P2B2/NP1PP1P1/P4n1P/RQ2KBNR w KQq -,26,1196,31745,1378427,39089172,1637102977 -1n4nr/3r1B1p/1p5b/p1p3kb/3pP1Pq/3P4/PQP1K2B/RNR5 w - -,40,1105,35786,1062213,33991882,1062998842 -6R1/5k2/8/2PP4/1K2p3/6p1/8/2r3q1 w - -,19,429,6486,162599,2387313,64245181 -1n3R2/3pBbk1/B6p/Pp4pP/P1qpPp2/5R2/5PP1/1R2K1N1 w - -,40,1154,40166,1148946,41340008,1160548180 -1k6/n6P/p1r2B2/P1p5/1P5P/1P6/4B2r/2N2K2 b - -,20,493,10768,261623,6235516,151336392 -1rb1qbn1/ppppp1p1/8/PB3k2/P2r3p/B1P2P1P/3PQ1PN/RN2K1R1 w Q -,36,917,32503,845496,29774016,795943391 -1r2rbk1/np2p3/1P3pp1/2p4p/1P3P1P/3Pn1Pb/1R1KB1q1/5R2 w - -,23,970,21263,897176,20288294,854560391 -2K5/8/6k1/8/1P2n1N1/6r1/7N/8 b - -,23,273,6003,82537,1816374,25762853 -rnbqkb1r/1p1p1ppp/p1p2n2/4p3/P7/1P2P1P1/1BPP1P1P/RN1QKBNR b KQkq -,28,1026,30801,1095857,34245244,1205146195 -8/1K6/p2Nk3/pN5r/P3n3/8/5N2/8 w - -,25,606,12915,279530,5671367,118961417 -1r6/3k3p/7P/3p4/p7/1p4K1/8/b1R5 b - -,26,528,12989,236309,5781193,97507285 -1k6/1bN5/8/8/1B1b4/6r1/4p3/4K3 b - -,39,575,19335,277288,8749450,126669870 -8/2k2N2/np6/2p5/1p3P2/8/4K3/8 w - -,15,141,1904,18958,242500,2526341 -rnb2r2/1p5p/4p1kb/p1P1n3/PQ2pPPp/2P1N3/4P2B/3RKB1R b - -,31,1079,31812,1096086,32481696,1115698519 -r1bk1b1r/1pq1pP1p/p2p2p1/3p2P1/n4Pn1/P1PKQ2B/1PN4P/RNB3R1 w - -,37,1237,38119,1250883,39947848,1310060533 -1r1kq3/6r1/p3pnpB/7p/P1p1P2P/1P3P1B/R2P4/2BK3R b - -,39,1133,42229,1266649,46180839,1417894649 -rn2k1n1/p4p1R/bqppp3/1p2P3/PP4p1/3PN3/2PRN1P1/2K1bBQ1 b q -,28,863,24393,782460,22343523,735953997 -7r/k7/6p1/p3p2p/PRr4P/3pnP2/5K1R/4B3 b - -,35,587,18340,373157,11153100,243321970 -3nkNR1/8/B7/8/Pr1P4/1P3P1p/K1p4P/8 w - -,25,382,8886,168006,4011553,84396602 -4k3/1r2p3/3nP1r1/p5pP/bN6/3n1P2/4KQ1P/5R1R w - -,31,1104,32741,1117314,34362620,1137969932 -2b2b1r/6kp/r3P1p1/pp1p1p2/PQq2B2/2p3PR/5PP1/R2KNB2 w - -,43,1307,48186,1533072,56910754,1865733169 -8/6p1/8/8/2K3n1/3R1bk1/7q/8 b - -,27,411,12329,183461,5947884,88876188 -1kr5/n6P/p4B2/P7/1Pp4P/1P6/4B2r/2N3K1 w - -,28,580,14126,325802,7996547,193460582 -6k1/8/b7/6b1/8/6p1/3p2P1/K1B5 w - -,6,144,1137,27500,243214,5862824 -rn2qbr1/N1pk1bp1/Qp2p3/5P1p/3PPP2/2pB1N1P/PP6/1RB1KR2 w - -,40,897,36464,896892,36565867,965893515 -5B2/3k3p/7P/8/5Pp1/2Rp2Kr/N7/2BR4 w - -,3,38,996,12546,353751,4825568 -2N3n1/8/4P3/P2k4/4b3/1K5p/6P1/4R3 w - -,25,403,9529,154030,3566657,60851497 -8/2k1P1b1/8/1p1pP3/1p3rB1/3K4/3n4/7q b - -,45,670,27239,387368,14833983,213754364 -1q2kbnr/1rp4b/p1np1p1p/1p2p3/1P5p/P1N2PP1/3P1KB1/R1B2QNR b k -,32,963,30774,935322,29921496,945226042 -1B6/1r3Bk1/1b6/Pp6/4KN1p/8/R7/8 w - -,37,755,25879,530125,17536353,363775858 -8/6Rr/2kb1p1p/Bn5P/P4N2/3P4/4K3/8 b - -,18,532,10504,289527,6020276,159959952 -rn1qk1r1/p2pn3/b1p2ppp/1p1Qp3/1P2P1P1/1P5P/P1KPNP1R/R1B2B2 b q -,19,667,13107,450808,9699588,331340028 -Nb6/4B1qr/1p3n1k/5P1P/1pP3pN/p4R1P/P3B3/R2K4 w - -,29,796,24450,711650,21989949,672996226 -rn1k4/1b4b1/1P1p4/pP2p1pr/2PpPP2/B5PB/3N3P/1R2K2R w - -,32,876,27753,775604,24585616,700940128 -1nb1k1nr/6bp/p2p1q2/p1pP4/P1P1p1p1/Rr3P2/1P1NPNBP/2B1K2R b Kk -,47,1212,54073,1396715,59490486,1546919527 -1R6/r3k3/2Q3p1/pp1p1p2/Pb3P2/5qP1/2pB2P1/R1K1N3 w - -,42,921,31426,719478,24263455,586494139 -3n4/r3k3/8/5P2/2p4n/2N5/3R2B1/2K5 b - -,22,695,14791,432815,9646576,267286407 -2N5/3r1k2/4p3/p4p2/P4Pp1/8/N7/4Kb2 b - -,26,234,5449,59645,1366400,16287524 -r1b1kb2/p2p1r2/n3N2p/1p1ppppP/1P6/P3P2R/2PB2P1/RQ2KBN1 w Qq -,36,757,27806,617206,22862775,533813014 -1r2Nrk1/np2p1b1/1p3pp1/1qpn3p/PP5P/1R1P1PPb/4B3/3KR3 b - -,40,762,29018,604652,23229351,519467092 -8/p3k3/P7/1N1p2q1/3P3p/7P/8/B1K5 w - -,4,92,903,21627,221401,4996822 -N2q2nr/bp4k1/8/5Ppp/pp4PN/B1PB3P/P7/R2K3R b - -,39,950,34203,947382,33806914,983779062 -8/b3k3/5n2/1P3RP1/2Pr3N/p6r/6K1/8 w - -,18,584,9838,302133,5158998,157267052 -8/8/k5pr/B3p2p/P3RP1P/3p4/6KR/8 w - -,25,200,5262,61450,1658422,23411522 -1q1k1bnr/p4rp1/n1pp3Q/P6p/1p2P2P/1P1P1PPB/2P2K2/RN4NR b - -,30,1054,29705,1024716,29509259,1013940974 -q1r5/p2bn1p1/P2pR3/1pP2P1k/1B1P3p/1Q5P/1R2KN2/8 w - -,44,1254,51381,1472399,59164952,1693228426 -rn2k3/pb6/P1ppp3/1pqPP3/1P3np1/2P3b1/3RN1PQ/2K2B2 b q -,32,823,24776,660460,19753369,541884181 -b3nbr1/2q1pBp1/1k6/3p3p/P2P4/5n2/2QK2p1/6R1 w - -,5,190,5721,173258,5181350,163291647 -3rk2r/2p1ppbp/n4npB/pp1p2q1/1P1P2b1/P1P2Q2/3N1P1P/1RN1KB1R w - -,39,1501,53753,2079536,75081506,2905557275 -rn2kb1r/1p2pppp/1q3n2/p1pp4/P1P2Pb1/8/1P1PP2P/RNBQKBNR w kq -,21,816,19282,739981,19023030,723651066 -r2n1r2/4k2p/1p2p3/5Pp1/P5P1/5b1P/1R1K2R1/1r6 b - -,41,779,31246,641547,25675183,545749568 -4q3/r3bk1b/1p2pnpr/p1pP3p/P2P1PPP/1QN3NR/1P1B1KB1/R7 b - -,35,1663,57233,2660777,91626837,4198523908 -8/4kB2/7R/4nP2/7K/1p2B3/8/8 w - -,33,391,10814,120796,3473715,38408927 -6k1/6N1/3R1n1p/3p2pP/pp1P2p1/8/2P1K3/R3Q3 w - -,37,462,17719,208987,7906545,89267963 -1k6/8/6b1/3pn1p1/2n5/N2p4/8/3K4 b - -,26,145,3663,25483,619215,4648785 -3N3k/1n2r3/7B/8/2K3p1/6P1/8/1b5R w - -,27,489,11045,220935,5073776,107358620 -b4k2/6R1/1P6/p3bBP1/P3P3/8/3K1p2/8 w - -,24,489,10249,202676,4197814,87698893 -5B2/P1k5/7P/4P3/2K1b1P1/8/8/8 b - -,19,338,4707,87051,1094503,21235484 -2k5/8/P7/PP1B4/3N3P/8/5r2/6BK b - -,18,433,6313,148029,2086987,49714124 -3R4/1Rk5/8/p3b3/7p/3K1B2/2r2P2/r7 b - -,1,26,907,21150,689884,15536232 -1rb4Q/4n3/1N2k1p1/pP1p1p2/Pn3P1P/3p4/3BP3/2R1KBNR w K -,45,701,28764,493664,20022824,368237068 -5brn/1bk5/P1pr3p/2B2PpR/p1Ppp1P1/N4QP1/R2PB3/1N3K2 w - -,36,738,27472,593913,22508550,509876757 -rnb5/4b1kr/1R1pP3/4N2P/pP2nP1P/p1N5/8/1KB4R w - -,37,1130,38034,1153122,39016084,1195014200 -4kb1r/4p1pp/2p2p2/p3PP1n/2Ppq3/4n2N/1rR1K2P/1N3BR1 w - -,22,911,14827,607431,11632763,469714159 -8/8/4N3/1p1k4/8/8/4K3/8 w - -,16,110,1415,9597,115738,826289 -N7/6nr/1p1B1P1k/8/2P3P1/1p1B1N2/P1Rq3b/RK6 b - -,28,871,24598,776825,23070172,738903514 -8/7k/5b2/R3B3/3p2P1/5r2/3N2K1/r7 b - -,35,863,27164,704821,21080918,548650972 -k5n1/b7/5P2/8/3p2Pp/R2B2bP/b3KN2/8 w - -,26,441,11824,226618,6019782,123849364 -4B1nr/pppr1p1p/4k1bq/2b5/1n1pPpp1/3P1PP1/P1PNQ2P/R1B2KR1 w - -,27,988,27668,1008188,29616852,1075594517 -r4b1r/p1n1pkpp/3P1nb1/2p5/3p1P1P/P2P4/1NQ1P2R/R1B1KBN1 w - -,34,1021,35108,1029013,36105817,1057883867 -B1k2bn1/p4r2/1P3p1B/P1p1p2P/2P5/2R2N2/4N3/4K2R b - -,19,754,14139,553133,10473607,408285160 -rn3k1r/1b2p3/1N3ppb/pPpP1Q2/5P1p/P3P3/RP4Pn/2B1K1NR b - -,28,977,26251,921888,25587384,907137791 -r1bk1b1r/pp1nqp1p/2ppp1p1/7n/1P1PN1P1/B1N1Q3/P1P1PK1P/1R3B1R b - -,30,1129,34444,1329748,41188653,1609328868 -1r3rk1/np2ppb1/1p3np1/2p2b1p/PPq1N2P/3P1PP1/4B3/1R1KR3 w - -,23,981,20855,892739,19469247,833297650 -8/8/7k/6np/4P2p/8/2R4K/1B6 b - -,10,168,1702,32215,323056,6317320 -1n3b1r/5k1p/3Q4/ppp4b/P2pP1n1/3P4/2P1K2B/RN6 w - -,37,670,18857,382583,11039809,243850199 -7R/r7/8/2B5/1N2kP2/7p/4KR2/6b1 w - -,34,594,19356,330138,10827227,193437143 -8/8/1k6/1pNq4/1p1p4/8/2K1B3/5n2 w - -,21,606,9294,257475,3939591,107444074 -8/8/1k6/8/1n6/1K4p1/4r3/8 b - -,29,130,3352,12769,316378,1397906 -8/5k2/1R5r/2K5/5P1p/p5b1/8/8 w - -,20,377,6388,125149,2075929,42845095 -N7/6k1/8/8/4BQ1K/1p5p/8/8 b - -,4,152,813,29679,221319,7625053 -8/3k4/7P/4P3/8/1N2K3/8/8 w - -,16,109,1664,8913,135365,764476 -r3kb1r/pbnpp2p/2p2p2/R6p/1p1PPP2/4BN2/2P1B1PP/1K5R w q -,47,1183,51601,1327820,54896930,1443345278 -8/7N/8/8/1k4nP/8/K7/4bR2 w - -,17,268,4949,80551,1545510,25632842 -8/3k1p2/r7/p1Brp1Rp/1b6/p1PN3b/R2K1P1P/7B b - -,31,1015,30667,1033871,31113641,1067739565 -8/8/2B5/5k2/1p1p4/1p6/8/6K1 b - -,9,144,1302,18073,166603,2222943 -rnbqkbnr/ppppp1pp/5p2/8/2B1P3/7P/PPPP1PP1/RNBQK1NR w KQ -,34,577,19359,373672,12571572,270766188 -rn5k/3p2q1/1pp1p3/pR3pp1/P4P2/4Q3/2NK1Pb1/2B3N1 w - -,41,1194,43644,1235949,43862715,1241836425 -1k1bRb2/8/B7/8/3p2PP/3K4/4N1b1/8 w - -,23,451,10668,222543,5466380,118696831 -3k4/8/Q6r/Rp1KP3/2p3bP/1PP2p2/8/1NN5 b - -,24,627,11834,330210,6061101,175968051 -1r1k2nN/7B/3p4/3Pp1b1/4R1R1/5P1p/7q/2nK4 w - -,22,800,18628,673669,16187745,582660321 -4k1B1/P7/P7/1P3r2/3N3P/8/8/6BK b - -,17,410,5887,146161,2100831,53946390 -8/2P4b/4Pn2/P1k3N1/7p/K1p1N3/6P1/6R1 b - -,20,600,10884,325756,5904921,177585265 -r3kb1r/p1p2ppp/2n4n/1p3bq1/P2pp1PP/1PN2P2/2PPP3/R1BQKBNR w KQkq -,26,1166,30119,1307169,34774744,1484852572 -8/6b1/r2n2Bp/P1k1p1p1/6P1/2PPP2P/1R2b2N/B3K3 b - -,25,660,15951,415723,10139775,263840094 -5k2/3n1Q2/8/7p/7P/4r1R1/3K4/8 b - -,1,14,284,4279,86014,1328089 -5bk1/3n3r/pp1p2Bp/PP4pP/2bP2p1/1R2KR2/2P4N/5Q2 b - -,25,971,22183,849767,19556161,741524840 -rnq2b1r/N1pkp1pp/Qp2b2n/3p1P2/2PP1P2/5N1P/PP2P3/R1B1KB1R b KQ -,24,848,19004,675207,16164641,578492003 -2b1kb2/3npr2/PBp3p1/3PP2p/1rP5/1N1R2P1/p4P1P/3K3R w - -,36,1102,35977,1172250,37376526,1261719196 -1R6/r3k3/Q5p1/pp1p1p2/P4P2/4BqP1/2K3P1/R3b3 w - -,43,979,32625,761246,25442814,609755797 -r2q2nr/p1pbkppp/2npp3/1p4P1/1b1P1N1P/2N5/PPP1PP2/R1BQKB1R b KQ -,29,777,21880,630054,18623880,571548710 -8/8/2N1kb2/6P1/N1P5/Np3bp1/8/3R1K2 b - -,23,600,11980,299592,6061162,148484405 -rnbq1bnr/4k1pp/Pp2p3/2pp1p2/P1P3P1/B4P1P/3PP1B1/RN1QK1NR b KQ -,29,690,20601,533878,16716156,465106289 -5k2/6p1/1p4q1/p4pN1/P1RKPP1p/1b5n/7P/3R1q2 w - -,26,867,18964,680412,14779925,545013138 -5bnr/1p3k1p/5p2/1q2p1p1/ppN3P1/B1P1pP1P/P2PKQ1R/4R1NB w - -,25,769,20392,624990,17708702,546291379 -5rk1/8/7P/1p2Q2r/3N4/Ppb3KB/6n1/8 b - -,33,1117,30149,987775,27570202,877033918 -3rk2r/2p1ppbp/n5pB/pp1p4/1P1Pnqb1/P1P2Q2/3NNP1P/1R2KB1R b - -,52,1666,81101,2738119,125922950,4371101755 -8/8/P7/2p5/P1P2p2/2k2N2/6K1/3R4 b - -,5,150,819,20915,114184,2723276 -8/3n4/k7/3R4/1K6/8/2p4P/3b4 b - -,17,331,5816,100973,1975325,32575841 -k7/8/8/3K4/2p4r/2P5/4N3/8 w - -,10,137,1507,22573,246591,3844867 -8/r7/8/1p6/4k3/6p1/6n1/1K1R4 w - -,15,328,4916,105431,1612171,34609660 -8/1bp5/1p3N2/1p3p2/1k3P1p/1n5K/8/r7 w - -,10,327,2407,76771,586917,17294148 -B3n3/4r1b1/3k2pp/P3p3/6P1/2PPP1nP/RB1Nb3/4K3 b - -,28,720,18852,489620,13402409,351329828 -1b6/8/p3kR1p/P7/8/2Q5/4b3/4R1K1 b - -,3,129,1705,67581,946778,37262109 -8/8/r1N5/PB1k4/8/1P3PRp/7P/2K5 b - -,8,207,2119,59765,714384,20187675 -5k2/2B2b2/7P/P3P3/6P1/3K4/8/8 b - -,12,163,1801,26241,297461,4528165 -1rbk3r/1p1p1Q2/p1Bb1n2/q3P2p/5p1P/1PP1PP2/P2K2P1/RN4NR b - -,36,1249,37558,1306666,39467881,1363476102 -4r3/2k5/8/1R6/3K1P1p/p5b1/B7/1r6 w - -,27,884,19280,591556,12610916,376366479 -1r1qkb1r/1bppp2p/1p3np1/p4p2/P1PnP3/3BBP1N/1P4PP/RN1QK2R b KQk -,37,1386,50077,1857193,66431176,2465963438 -8/3k3p/2b3BP/3p4/p1pb1B2/4r1p1/3K1R1r/8 b - -,41,812,29266,610453,21517215,471634230 -r1b1kb1r/p4ppp/3p1n2/1pp1q1P1/P2p4/8/RPK1PP1P/1NBQ1BNR w kq -,31,1229,35506,1399722,42088017,1645466118 -r1b4n/1pp3r1/pk1p1p2/4P1bp/1P3pnP/N2K1PP1/Pq6/4RBNR w - -,27,1184,25395,1094209,23998443,1020315821 -rnb1k3/p7/Pqppp3/1p1nP3/1P4p1/3P2b1/2PRN1PQ/2K2B2 b q -,35,763,23481,540121,15988624,383978220 -1rbQ4/8/1Nn1k1pn/pP1p1p2/P4P1P/3p3R/3BP3/2RK1BN1 w - -,43,659,27553,453420,19018668,331940403 -8/2k2N2/3R4/4b3/2K5/5N2/8/6b1 b - -,21,654,12013,347609,6305650,174672248 -r4n2/6kp/2p4b/p5PP/5p2/K7/5B2/4R3 b - -,16,440,7451,186496,3460550,81788935 -7r/1k6/3K4/6n1/6p1/8/8/8 b - -,27,136,3428,16684,405669,2159625 -r7/2p3r1/P3knPp/P2p4/3Pp1bP/1P1nKR2/1B3R2/1B6 b - -,39,907,32554,804004,27822274,709434122 -1K2k3/4N3/p7/p7/P7/8/3N4/2r5 b - -,19,270,4489,64826,1034241,14971924 -k5n1/4b3/3pb3/3PbPp1/2P2RPp/p1N1KN1P/8/1B4R1 w - -,35,732,22209,494428,14925069,345139360 -rnb1kr2/p2p1p1p/1p6/2b3p1/2P2qP1/1PNPP2n/P2KN2P/2RQB2R w - -,24,924,23270,878659,23473705,884671799 -2n5/3r4/5p1p/3k3P/P5R1/3P3N/3B2K1/4b3 b - -,23,699,15695,442775,10149609,274045926 -1Qb5/q3b1k1/pp2p3/1Pp1P2p/P3B2P/1n1K4/2P1P1NB/2r2N2 b - -,31,924,28018,829657,25233510,741208262 -5k2/3P4/p7/P7/N1p1p1BQ/8/7R/4K3 b - -,5,197,904,36785,166462,6846366 -5b2/8/8/Pk2p3/2b4p/2P1Pr2/1Bn5/1K5N b - -,38,331,11927,120416,4169323,46571292 -k7/4r3/8/3KN3/8/2P5/8/8 b - -,13,177,2656,33287,513333,6275457 -5n1k/8/6p1/4p2p/7P/b7/7K/5B2 b - -,14,168,2600,31435,513209,6501792 -1N6/4k3/2K5/1p2P3/R1N4P/2P2p2/1r6/8 w - -,24,407,10067,161121,3970930,62816308 -8/8/3p4/6n1/3K2k1/8/8/7B w - -,12,145,1817,20492,267344,2972336 -rnb2k2/1p1p1p1r/2p2nPp/1pb1p1P1/P7/1qB1P3/2PP3P/RN2KBNR w KQ -,33,1422,44995,1884769,58929251,2418166796 -3rkbnr/pb2ppp1/np6/2pp4/P1PPBq2/4P3/NP3PPP/R1BQK1NR w Kk -,37,1665,58550,2514983,88849159,3729347521 -8/2K4R/6bq/6B1/P5k1/8/8/8 w - -,24,580,11792,293691,5850276,154499202 -8/5bk1/B3RN2/6P1/1P6/p5B1/6K1/7R b - -,8,431,4263,202890,2233870,99689517 -4n3/R7/P1p5/5kp1/r7/1PB5/2N1K3/b4N2 b - -,24,826,17283,548022,11651093,353450080 -2b4B/b2kr3/7p/N1P4P/4p3/Pn6/R2P3N/4K3 b - -,22,523,12273,292273,7296495,176622376 -r1bqkb1r/p2p1ppp/1p3n2/2p5/Pn1p1BP1/7B/RPPKPP1P/1N1Q2NR b kq -,31,848,27363,777164,25998799,767117129 -8/1Q2k3/8/p2p1p2/R3bp2/4B1P1/6P1/4bK2 b - -,6,246,3310,113730,1595347,52878572 -4Q3/3P1k2/p7/P7/N7/7B/4p3/4K3 b - -,2,64,229,7504,31876,1063511 -rnb1k3/p5R1/Pqppp3/1p1nPp2/1P4p1/3P2b1/2PRN1P1/2K2BQ1 w q -,30,909,27143,794231,23561321,676245699 -1r6/8/1k6/4B1pp/P4P1P/8/4R2R/3q3K w - -,2,69,1735,54544,1446381,45908365 -r3kbnr/p1p2p1p/b3p1p1/1p1pq3/4P1PP/N2B4/P1QPKP2/R1B3R1 w kq -,32,1284,40641,1562977,50184262,1881050419 -rn4r1/p2kp2p/B1pB4/r3np2/P2b3P/5N1R/1P2KPP1/6R1 w - -,37,1350,49968,1781403,64895531,2281815742 -1B6/1r1N3r/nP3bk1/1b2P3/3K2pP/6P1/2R5/4R3 w - -,36,1212,37635,1207441,36546248,1152998149 -1r1q1rk1/np2pp2/1p3npb/2p2b1p/P1PB1N1P/3P1PP1/1P1NB3/2RK3R b - -,37,1227,44443,1438454,52523178,1666146100 -1kbn4/8/1p6/5PpN/8/KRpp4/7P/8 w - -,16,262,4711,81740,1537427,28336627 -k7/3B4/4p3/K3P2p/4P2P/8/7N/8 b - -,3,38,152,2171,8342,124972 -r7/2k2n2/2qN4/2PPp3/Q1P1R2p/K4Pp1/8/R7 w - -,32,884,27225,722822,22952081,604028401 -r2k1b2/p3p2R/n2n4/p1Qb4/1P1pp3/B2N1N2/5Pp1/1R4K1 b - -,32,1574,44033,2089656,57461563,2643499354 -8/2n4k/1p6/8/K7/8/4n3/5b2 w - -,3,60,305,6611,30857,702641 -8/k4r2/3r4/1P1N4/K5p1/8/8/6n1 b - -,30,362,10487,116524,3333637,36688998 -6n1/b3k3/1P6/2P3P1/5r1N/p4R2/r7/5K2 b - -,30,390,9560,155903,3965045,70621341 -6k1/8/8/4b3/8/5K2/5B2/1b6 b - -,25,325,7331,95674,2081320,27178913 -rn1k4/1b4b1/1P1p4/pP2p2r/2PpPPp1/BN4P1/6BP/1R2K2R b - -,30,915,27211,839048,24863128,772430122 -2b1kb1r/r1p4p/p1n1p3/1p4PP/2Pp1K2/PN1P4/1P2Bn2/R2Q2N1 b k -,33,776,24907,624682,19728303,521059114 -5k2/1N3r2/p4b2/p1p5/P4n1P/N7/5R2/5K1N w - -,21,619,14389,400317,8714114,230637901 -8/3kB2Q/3pp3/2n4P/2pP3b/8/2R5/K6B w - -,38,574,20950,324135,12015554,186024805 -r7/1b2k1b1/nP1p4/pP2pr2/2PNPPp1/B5P1/1R1K2BP/7R b - -,35,1351,43768,1639588,53072287,1940157064 -8/3R3N/8/8/1k5b/5n2/K7/8 w - -,19,338,6518,111068,2158555,36273309 -k7/8/p1b5/r7/2R5/8/3pKB2/8 b - -,27,607,15363,326388,8256324,170965823 -8/1BN1k3/6P1/1P6/8/pb6/5B2/4K1R1 w - -,32,443,14320,183212,5994989,74621685 -8/8/4k3/1P6/8/6BR/5K2/nb6 w - -,22,316,8132,117713,3053453,45175291 -7b/3k4/1p5N/PP6/4Kb2/8/1R4B1/8 w - -,23,521,12246,257631,6240667,126340214 -1n3R2/3p2k1/B6p/Pp1b2BP/P1qpPp2/5R2/5PP1/R3K1N1 b - -,30,1010,28537,971678,27347701,943575525 -rn2k2r/1b1p2bp/1PQ1p1Pn/p4pq1/1P1PP3/5N2/P4P2/RNB1KB1R b KQkq -,41,1924,73005,3344835,126264209,5654822517 -4k1nr/2p2p2/p3r1pp/1P1p3q/Pn1P1P1P/1P1bP3/4R3/RBBNK3 b - -,39,947,36555,854150,32717046,760190322 -2b1kb1r/r1p1p2p/p1n5/1p3q1P/2Pp1B2/1N1P1K2/PP2BnP1/R2Q2N1 w k -,24,1023,23199,969675,24434635,1003470116 -2k5/K7/8/4P3/1N1R3P/4rp2/2p5/8 b - -,14,282,4329,85009,1523611,28978759 -Br2rB2/b7/p5kp/P7/1PpNP3/3p4/8/2RK4 b - -,25,604,16378,392478,10869501,265217902 -8/4r3/8/p7/P2b1P2/4k3/6N1/1K6 b - -,6,39,1110,8885,230063,1998573 -r1bqkb1r/pppppp1p/2n2n2/6p1/4P3/2PP1K2/PP3PPP/RNBQ1BNR b kq -,25,650,17414,472741,13321499,372861414 -r1bqkbnr/p2ppppp/np6/2p5/1P6/5PP1/P1PPP2P/RNBQKBNR w KQkq -,22,460,10867,253898,6389155,164501481 -8/8/3p4/8/1K3k2/5n2/8/8 b - -,16,107,1587,9133,128229,776813 -1nqk4/5N2/2rP4/R3KP1p/1PR5/3p1P2/4B3/5q2 b - -,2,71,2213,62626,2089577,54759695 -2k5/5n2/1p3r2/6p1/K3b1P1/2pp4/1R5P/6N1 w - -,20,662,11597,356546,6115807,182740885 -1k3br1/8/1pR5/pP2pp2/B3n3/8/P1R4K/3N4 b - -,27,687,17457,446746,11404632,298394495 -8/8/7k/6n1/7p/1P6/2K4p/2R5 w - -,14,210,3804,58301,1001054,16244750 -2N3n1/8/4P3/P1k2bN1/8/1K2N2p/6P1/6R1 w - -,33,495,14827,235246,7160661,117066936 -1R6/p2r1k2/PN1n4/8/3p2K1/B4p2/8/4b1n1 b - -,28,626,16541,384585,10125055,233685478 -1r6/p1p2kp1/n3b2p/Pr2P3/2PbP1P1/1P3PN1/1RK1N2q/8 b - -,52,834,41984,756019,36789367,709326204 -8/p7/PN2q3/5k2/1K1P3p/8/1B6/8 w - -,17,478,6138,160899,2079947,51262492 -r1bq1bnr/pppk1pp1/2np4/7p/3PPp1P/6P1/PPP1KP2/RN1Q1BNR w - -,28,861,24532,764370,22821415,723774483 -N5nr/bp6/7k/5Ppp/pp1q2PN/2PB3P/P7/R1BK3R w - -,26,786,21283,679545,19415061,637850398 -8/b1k5/4P3/7B/8/7Q/2K3P1/8 w - -,30,377,11511,128396,3990298,47008650 -1n1rkb2/p7/2n5/3b4/pP1p4/1R1N1pK1/5P2/B5n1 w - -,18,545,9806,308813,5832811,189552885 -1n1K4/8/2k1b3/2p5/3p4/8/8/4B3 b - -,20,187,3419,32774,588889,5928804 -4r3/7p/1Bbb2kP/p2pP1r1/B1p2P2/2p3p1/2R5/3K4 b - -,33,885,27767,702782,21723332,536127209 -8/6N1/1p6/8/4kP2/2K5/8/8 w - -,11,63,726,4912,56805,405243 -r1Bk1bnN/q7/1p1p4/Bb1Pp1p1/4np1p/5PP1/2R5/4K1R1 b - -,40,1297,48765,1493013,55701934,1657796049 -8/8/8/3Bk3/1p1p4/8/7K/1b6 b - -,14,231,3329,45501,665962,8707136 -1n2K3/8/2k5/2p5/2bp3B/8/8/8 w - -,10,194,1936,34591,360067,6379209 -6k1/6P1/n7/r6n/1p1p1p1p/1P5P/3K4/5b2 b - -,27,114,3087,15659,425242,2482667 -rnb1kb1r/ppppqp1p/4p1pn/8/1P3PP1/7N/P1PPPK1P/RNBQ1B1R b kq -,27,639,18830,466232,14645615,381971143 -r1b3nr/3pqpb1/4Nkp1/pppP3p/1nP5/P4PP1/3RP2P/3QKBNR b K -,30,902,28049,861685,27427480,862666131 -2n5/6k1/1P6/8/3P3P/8/6K1/1N4Q1 b - -,12,252,2286,58984,540833,15065536 -3r1n1k/7p/2p4b/p5PP/5p2/K3R3/5B2/8 w - -,23,485,11064,225883,4997602,103953326 -2B1k1n1/r1n2p2/2p3r1/1pBPp1q1/P4P1P/N1pP4/6Q1/2R1K2R b K -,37,2041,75559,3779344,140520118,6581688085 -2b1rb2/3k3P/4n2p/2P1B2P/2N1p3/1R6/PR1P3N/4K3 b - -,19,838,16433,692037,14908216,614757108 -rnbqk2r/1ppp4/1b2p1pn/pP3p1p/3PP3/5PK1/P1P3PP/RNBQ1BNR w kq -,32,979,27778,885259,25516750,836792697 -rn2q2r/pkp2ppp/1p3N2/2bPp3/P3PP1P/6P1/1P1PK1B1/RNBQ1R2 b - -,36,1203,41782,1440593,49163715,1733720903 -7b/1r5n/1B2k3/1P4pr/2P2p1P/p7/8/2R1N1K1 w - -,24,709,16725,479734,11429311,330289723 -1n3r2/1k3p2/1p5b/pPp1p3/B5K1/2n1R3/PN6/2R5 b - -,28,828,23222,665391,18835404,535902467 -3B4/1k6/8/4qPpp/Pr5P/7K/8/R7 w - -,19,843,14247,545218,9707793,347484910 -N4b2/7r/1B3P1k/8/qpP3P1/8/B1n5/2K2R2 b - -,31,796,23736,583521,18255366,444464769 -2b4r/6R1/5P1k/2p2P2/5R1P/6Pp/7K/1r6 w - -,24,566,12675,301555,6888912,170045893 -1r1r1bk1/1p2p3/1Pn2ppn/1Pp4p/R2P1P1P/R7/3K4/q2b4 w - -,21,832,15952,658495,12351002,519062266 -6r1/3N4/2b1P3/r3b2P/2pk4/3Pp3/1p1R4/3K4 b - -,53,833,39246,663557,29460549,520430990 -7n/8/1P1kN3/P2p3P/5pb1/1p1P2R1/6K1/7N b - -,18,336,5814,113593,1895718,38540481 -4k3/nb6/5n2/P1p5/2PpP2N/1p1P3K/8/6b1 b - -,25,204,5027,50934,1237840,13041072 -8/4k3/1P5Q/3n4/3P3P/8/4K3/1N6 w - -,27,254,6407,62905,1696762,15440746 -rnbq1br1/pp1pp3/2p2pkp/1P4p1/3Pn3/P1NN3P/2PB4/R3KBQR b KQ -,31,1230,36381,1448549,43507029,1739932074 -1k6/8/P7/2p5/PNP2p2/8/6K1/5R2 b - -,6,118,638,12612,70465,1428680 -6r1/7k/n7/3B4/6K1/8/2bp4/3R4 w - -,6,153,3319,88396,1865461,51724292 -5N2/5B2/Pb4Pk/8/3p3P/8/2R1p3/2K1N3 b - -,8,224,2260,60655,684201,18354762 -5b2/r1B5/nP4k1/pP2Pb2/2P3p1/1N4P1/5KBP/1R1r3R b - -,41,1321,50309,1654153,60167588,1986931064 -4r2r/4p3/b4P1k/2p2P2/7P/4b1Pp/R6K/1q5R b - -,48,932,42362,879131,38747941,843266875 -1n6/8/2k3K1/2p5/2PpP1nb/3P4/8/1b6 w - -,6,137,752,16901,90769,2053788 -1r3kn1/Np1b3r/N2p1q2/p7/PBP2p1p/3PPP1Q/1P4PP/3RKB1R w - -,34,1421,48594,1899913,66071078,2490952234 -k4b2/8/7N/7P/2p1bK2/P1P1p1P1/1rN2PR1/8 b - -,31,572,17318,325256,9655540,186258618 -3r4/6k1/8/6N1/Pp1qp2N/2RP4/6K1/1r6 b - -,42,870,33611,703958,27706331,585536311 -rn2kb1r/p2ppp1p/bq3n2/1pp5/1P3p2/P1PP4/3NPPPP/RN1QKB1R b KQkq -,28,589,17940,411320,13071714,319733683 -1rr3n1/1p5k/1P2p1p1/1Pbb1p1p/1n3P1P/8/5R2/3K4 b - -,34,413,14925,181833,6731267,83958736 -r7/4k2p/4n3/1p3pp1/r5PP/8/4K2R/8 w - -,15,627,9656,373735,5844459,212760779 -7k/3b3n/1R5P/3B4/4bK2/8/8/8 b - -,21,568,11078,274272,5272348,126632720 -1N6/8/4Q3/2k5/3pbr2/2NP2K1/4Q3/1R6 w - -,63,978,52955,808558,41964432,652674123 -2Q5/3r4/k1q5/4R3/6K1/7p/5B2/8 b - -,3,120,2683,77007,1966630,59410675 -B6k/8/6KP/8/8/3b4/8/5nR1 w - -,5,73,1431,20098,431511,6042721 -2r3nr/1q2pk2/8/2p1P3/4BPpP/3bb1P1/6K1/R5NR w - -,25,1112,26628,1151941,28828957,1230732353 -1rb1kb1r/pp2p1pp/n4p2/2pp1n2/4P3/2PP1N1P/Pq4P1/RNBQKB1R w KQk -,33,1270,38795,1450259,44964280,1667946231 -1rb2rk1/np1qppb1/1p2Pnp1/2p4p/2Pp1N1P/P2PBPP1/1P1N4/R2K1B1R b - -,27,808,22196,674002,19294407,588150242 -1nr2k2/7r/1p5p/p7/b1P1pp1p/6N1/4PKB1/b3R1nR b - -,46,913,40209,853896,36359937,827247925 -rnbqkb1r/3p1p2/pP2p3/2p2NpQ/1P3P1p/3PP3/1BPK2PP/RN3B1R b kq -,25,1237,31286,1457642,39213449,1760136860 -1k3r2/2b5/p7/Ppp2pP1/3RQB2/3K3b/RP5r/8 w - -,38,871,29600,743536,25320008,675053414 -3Q4/6k1/1N2b1p1/1P1p1p2/Pp3PnP/3P4/4RNB1/4K3 b - -,16,701,9721,410357,5683150,235824085 -4b3/3k4/P2B3P/2K1P3/6P1/8/8/8 b - -,6,78,790,11922,118658,1860564 -b1k4r/7p/R1n1q3/p1Pp4/P7/3p4/2NP2Kn/2B5 b - -,41,649,23559,378186,13291556,221499463 -R7/2k5/3b4/p4p2/4p2p/R1r4B/3K1P1P/1r4N1 w - -,26,937,22466,749775,18538809,588525728 -1N6/6P1/5k2/r2b4/3p4/3P3K/8/QR1N4 b - -,30,806,20415,627645,14418368,481005774 -5n2/3r2kr/8/3R3p/p1p4p/4PB2/Rb2K3/2N5 w - -,30,814,24741,704887,21793206,636867710 -r1bqkbn1/p2p1pp1/np5r/2p1p2p/1P3N2/3P1PP1/P1P1P2P/RNBQKB1R w KQq -,31,1039,32521,1066043,33549075,1104471909 -rnbqkbnr/pppppp1p/6p1/2P5/8/8/PP1PPPPP/RNBQKBNR b KQkq -,20,442,9811,248473,6038154,169186117 -8/rppP1r2/pk6/1P2npPp/1K3p2/N4PP1/P7/4nbN1 w - -,16,453,7088,202471,3552164,102628542 -8/r7/2R5/1k6/pN6/Pb1P1K2/7r/8 w - -,24,722,15111,434677,8899825,249941168 -8/7R/b7/k7/N5PP/2K5/8/8 b - -,9,180,1762,36864,382021,8155404 -8/r3b1kB/8/7n/2np2r1/2p5/4K1b1/3R4 b - -,53,929,47764,822785,40946771,712300053 -1k5q/4b3/6P1/7n/8/3N4/7K/8 b - -,32,348,10942,111965,3545673,35902704 -1nb4k/3ppp1r/6p1/qPp1b2p/5PPP/Bp1PP3/R5B1/1N1K2NR b - -,40,1283,48419,1563353,57193203,1858070997 -rnR1b2r/4b2k/3pPn1p/8/pP2PPpP/p7/2KB1P2/1NN4R w - -,31,858,27508,785564,25132606,745141898 -2k5/4Br1Q/p3b3/P7/1P6/3p4/8/R1K5 b - -,23,601,12904,367431,7599134,227342299 -r1b1kbnr/1p1p3p/6p1/p1p2p2/4PB2/P1q2N2/4KPPP/R1Q2B1R b kq -,40,1179,44858,1396804,51047210,1664735295 -1kb1nb2/8/3p4/3Pb1p1/p1P2PPp/4K2P/3R1N2/4N1RB b - -,26,651,16436,415339,10419772,268153175 -8/3NbB2/P5P1/2R5/3p2kP/8/1K4N1/4r3 w - -,36,761,23632,506028,15463563,326070207 -1bb5/3kr2P/4n2p/2P4P/2NBp3/P7/1R1P3N/4K3 b - -,26,877,20880,701429,17260920,575737135 -r7/p6r/1p3k2/q1B1p2p/Pb3pp1/1PnPQ2N/1R2PPP1/1N2KB1R w - -,29,1122,29265,1127423,30696481,1179677424 -8/4kP2/8/1P6/7P/p3b1n1/K3R3/8 w - -,18,271,5139,91832,1818625,31880924 -2b2b2/2nkr2r/5BPp/1RP1p2P/2p1p3/N4N2/PR1P4/4K3 w - -,34,732,25274,549018,19080102,429859722 -8/3k1p2/6r1/p2rp1Rp/1b6/p1PNB2b/3K1P1P/1R5B b - -,39,1309,47394,1679474,57918980,2105523558 -r5n1/5b2/p7/P1kpP3/2p1P2p/1B5N/3K2P1/3N2R1 w - -,24,497,12156,261972,6659664,148567491 -1k4n1/1p2B2p/3pp2b/3Q1p1P/2pP4/1R2P3/6B1/K5R1 w - -,42,666,28774,454741,19684193,314576517 -2b1k2r/p6N/B2pp2b/P2rP3/6Pp/6RP/2P2B2/1N1Q1KR1 b - -,27,1014,26567,1013518,26667300,1029270976 -k3r3/5K2/8/8/3P1N2/P4R2/8/8 b - -,16,325,5019,110317,1696859,38218790 -4R3/6p1/8/6k1/b2K2P1/8/2q2n2/8 w - -,17,584,7006,237206,2898789,96525042 -r2k4/n5b1/p2p2Q1/P1pP4/8/P2KBB1N/6pR/R7 b - -,23,1133,24490,1173361,26175007,1221179493 -3Nk3/p2p2r1/b6p/5P1P/1bBp2p1/P1n3R1/QrP3P1/3R1KN1 w - -,33,1046,35057,1106298,37716047,1185550807 -1k6/4n2P/p5r1/P1p4B/1P6/1P4RP/1N3Kb1/r1B3r1 w - -,32,1223,37487,1407239,43195128,1603487398 -r1bn3r/p1pk1ppp/7n/1P1N3q/1b1pp1PP/BP3P1R/Q1PPPK2/R4BN1 b - -,41,1290,49739,1580965,61328183,1982513166 -4k3/5n2/1p4B1/4r1p1/1K3R2/2pp1bP1/7P/1R4N1 w - -,33,947,29596,787661,24562277,648637583 -N7/6nr/1p5k/4bP1q/2P3P1/Bp1B1N2/P2R4/RK6 b - -,28,861,23738,747147,21543827,689291947 -3r1Nk1/8/4n3/8/P1BP4/KPp2P1p/2Q4P/7R w - -,39,498,18273,286055,10116459,171092713 -r1r5/8/5b1k/1p6/2Np2PB/1RN5/5K2/1r6 b - -,41,1078,40711,1103781,40946471,1111183470 -2r3nr/3k1p1p/N3p1pb/7P/bQp1PqP1/B4P2/P2P1K1R/R7 w - -,41,1407,52842,1838047,69969537,2462246606 -2b5/8/4nr1k/P2p1p2/1p3PPp/1P2R2P/2K5/7n w - -,18,358,5968,133623,2185878,51203278 -1r3br1/1bNB4/p1p3kp/2P1p3/1PR1P3/3p1q2/PB1K4/5RN1 w - -,39,1307,43691,1411381,47428477,1539674529 -rnb3r1/p2p1pk1/1p6/2N1q1pp/2P3P1/1P1PP2n/PR1K3P/1QN1BR2 b - -,43,1171,46309,1315608,50826394,1493926358 -k7/8/1R2nN2/6p1/8/K1pp4/7P/8 w - -,25,257,6177,64999,1464636,17023479 -2R5/1k2N2b/5P1N/1r5P/2p4K/2P5/8/2r5 b - -,31,700,19743,439894,12392732,276534401 -1r1r1bn1/1p2p2k/RP3pp1/1Pp4p/1n1P1P1P/5b2/3K4/8 b - -,35,452,15338,216321,7199461,105773343 -r4br1/1k2p3/n1p2npp/Pp1Q1b2/8/2PPP1qP/P4P2/RNB1KB2 b Q -,51,1687,73846,2271390,95410956,2858179589 -1n1rkbr1/q2bN3/1n1pp2p/1pp3p1/Q3P2P/PPPP4/4N1P1/1RBB1K1R b - -,31,1178,37124,1414056,45263132,1730413533 -5Q2/8/p2bk2p/P5qb/5R2/8/5K2/5R2 b - -,37,1027,26219,770634,20696293,633615699 -4k2N/8/4B3/2P5/8/8/8/1K6 w - -,19,61,1074,4417,76688,334686 -1k5b/7R/8/5N2/8/3K1N2/8/4b3 b - -,16,553,9126,282395,4758008,138972994 -1rbqkbr1/p2p2pn/1p2p3/2n4p/PPpP4/N6P/R1P1P1P1/2BQKBNR w K -,28,883,24612,787293,23026129,750909817 -rnbq1b1r/p2p4/1pp2pkp/1P1Np1p1/3PnNQ1/P6P/2PB4/R3KB1R b KQ -,4,192,5836,268108,8297361,369712856 -8/8/4k3/r6n/1R3p1p/3p3P/3nb3/2K5 w - -,14,408,5017,141957,1785600,49728848 -1b6/4P3/2b3r1/r3k2P/2P5/8/3RpK2/8 w - -,21,753,14098,510503,9526733,341899492 -8/5kN1/8/3rq3/P1R1pN2/1p1P4/7K/1r6 b - -,40,758,29302,593298,22591938,474012455 -1R6/6k1/3Q4/3NP2p/Pp2P2P/8/3b2K1/4N3 b - -,10,454,3930,174556,1564087,67938600 -r2qk1n1/p2p1pp1/bprb4/3N4/1n1p1PPp/2p1B3/P2QP2P/RN2KB1R w KQq -,28,1112,32126,1283262,39422967,1578069860 -6kr/7b/1p2pnp1/p3b2p/qQ2NPPP/R1Bp4/1P4BR/1N3K2 w - -,40,1012,40480,1113252,45328759,1307463951 -5k2/8/4nB2/5P2/8/2K2p2/8/8 w - -,16,163,2663,29182,458726,5144008 -r2nk1nr/p3p3/b1qp1p1b/1pp4p/1P3pPP/P1PP1N2/4PP1R/RNQK1B2 w kq -,29,864,25072,784614,23018537,741061216 -4r3/8/K3k2P/8/8/3N4/5p2/6b1 b - -,20,240,5552,61043,1525151,16499355 -5r2/p6k/P1P5/2P2r2/1R4PK/3B4/1P6/8 b - -,14,336,5839,127275,2547183,55304201 -rR6/6k1/4b3/1P1Np2r/pb3P1P/2n5/2K5/2B2R2 w - -,32,1145,35671,1282534,39866013,1422554476 -1r1b3Q/2Pk4/n7/2R4p/3p3P/8/5B2/3K4 b - -,22,862,15387,573146,10369037,378573128 -3k4/8/8/5n1N/8/1K1p1N2/8/8 b - -,14,254,3301,56744,735895,12261104 -1r3bn1/4pk1r/5p1p/pp5P/Pp1Q4/2N2PP1/q1RP2B1/1NB2RK1 w - -,41,1032,42347,1049583,42673027,1074326099 -3k1bnr/p2B3r/nqp3pQ/P2P3p/1p1PP2P/1P3PP1/8/RN3KNR b - -,29,1001,28400,973793,28529135,976536624 -6k1/8/1p6/8/1n6/8/2b4n/4K3 w - -,3,69,346,8125,36168,846295 -r2k1bnr/pp6/B3qp1p/1Pp1p1Q1/P1P3bP/R2Pp3/8/1NB1K1NR b - -,37,1145,40164,1329144,45186350,1555074992 -1k1n4/5b2/8/3p2p1/3K4/8/3N4/8 b - -,14,142,2242,22668,377676,3920297 -r7/8/5b1k/1p6/2Np2P1/1R4B1/5K2/rN5r b - -,44,1204,46796,1250103,46526861,1240763008 -3R4/2k5/8/p7/4B2p/1R1K4/2r2P1b/1r4N1 b - -,26,827,19842,628930,15755241,495822324 -r2n3r/1bNk2pp/6P1/pP3p2/3pPqnP/1P1P1p1R/2P3B1/Q1B1bKN1 b - e3,50,1630,76411,2468318,113665410,3693285671 -Q7/q2bb1k1/pp2p3/PPp1P2p/4B2P/1n1KP3/6NB/2r2N2 b - -,31,751,22717,569640,17816370,459306818 -8/1r2kb2/np5N/4P3/P2P1PP1/1b4BK/2B5/5R2 w - -,32,786,24079,597568,17898646,453046761 -rnbqkbnr/ppppp1pp/8/5p2/8/1P5P/P1PPPPP1/RNBQKBNR b KQkq -,20,399,8921,198366,4891220,119561165 -7Q/b1k5/4P3/8/8/8/4B1P1/3K4 b - -,11,389,3928,129619,1429928,45745447 -1rbk1br1/p1npp2p/2p2pN1/1R5p/1p1PPP1P/4B3/2P1B1P1/1K5R w - -,44,1312,53599,1557318,60185408,1729722981 -rn1qk2r/p1ppn1p1/b2b1p1p/1p2p3/4P1P1/1QP4P/PPKP1P2/R1B2BNR w kq -,30,686,21261,515374,16146876,414274809 -4k1nr/2p2p2/p3rqpp/1P1p2P1/Pn1P1P1P/1P2P3/7R/RBBNKb2 w - -,34,1243,36934,1373036,39559740,1482212181 -5knr/7p/p7/pNpPn3/P5P1/2rR4/1q1bKN1P/2B2B1R b - -,40,908,34877,814896,30994773,752347515 -8/1k5b/8/p7/7K/8/2r5/8 w - -,5,140,688,19220,94187,2619052 -2B1k2b/2N4N/Q7/P2p2P1/R6p/2r1p2P/4K1R1/8 b - -,4,177,2906,121112,2138936,89214978 -RB6/7p/2K4P/6kP/2p4n/1r3p2/8/8 b - -,21,384,7691,165194,3366363,74827062 -rn2kbnr/p3q1p1/2pp1p2/P2bp2p/Rp2PB1P/1PQP2P1/2PN1P2/4KBNR b Kkq -,26,875,23793,830044,23593778,842605736 -8/5k2/8/8/6Pb/1N1p1KB1/r7/8 w - -,19,520,9529,239797,4298508,104279517 -r5nr/nb1p1p2/3qNk1b/pppP2p1/2P4P/P3KP1B/3RP2P/1Q4NR b - -,37,1348,42834,1415536,45057380,1434774883 -rk6/2p1r3/5pp1/p2PpP1p/P1P1P1P1/7B/1P1KQ3/RNB2qR1 w - -,30,810,21075,579335,15902286,444151107 -rkr5/2p2p2/6p1/p2PpP1p/P1P1P1Pq/7B/1PQ2R2/RNB1K3 w - -,30,665,20796,507662,16557223,429662265 -rnbqkbnr/ppp1pppp/8/3p4/3PP3/8/PPP2PPP/RNBQKBNR b KQkq -,28,1060,30267,1136220,33887398,1266809011 -5knr/2p5/p1r4p/PP1p1ppq/1n1P1P1P/1P1bP3/RB1KR3/1B1N4 w - -,22,783,16988,605152,13600590,489048892 -3N2k1/7R/8/1p1pP1BP/P7/3pP3/3K2P1/3b4 b - -,12,336,3367,89073,876092,22613052 -rnbq2n1/1pppk2r/p4b2/1N2ppNp/8/3PPQ2/PPPB1PPP/1R1K1B1R w - -,46,1096,48892,1229887,53550959,1416743893 -4r1R1/8/8/5k2/3B1P2/3N3p/8/3R1K2 w - -,37,567,19917,292521,10238729,155064718 -Qqb2r2/4b1k1/pp2p3/1Pp1P2p/P1K4P/1n1B4/2PNP1NB/R7 w - -,40,1359,47448,1536203,52922428,1685673137 -2k3r1/1b5P/p2rNRP1/Ppp5/1P6/1Pn2B1P/8/1rB1K3 w - -,35,1090,34231,1063873,33500640,1051915464 -1r6/n6r/3P1kp1/pP3p2/P1b2PPp/3RP3/7Q/2b1K1R1 w - -,31,1141,32995,1180284,34030136,1188625169 -2k5/4rb2/8/p7/8/8/5K2/8 w - -,5,130,737,19454,102429,2724590 -1kr5/n6P/p4B2/P7/1P5P/1Pp2B2/7r/2N3K1 b - -,23,614,13785,355015,8171445,206348769 -8/3b4/2R2k2/8/3p1b2/B5p1/6P1/4K3 b - -,8,170,3290,63629,1264831,24304345 -r1bqkbnr/ppppp1p1/2n2p1p/8/4PP2/7P/PPPP2P1/RNBQKBNR w KQkq -,29,557,16560,352540,10695653,247063656 -3r4/p1p3p1/n2bP1kp/P1r3P1/6P1/1P1b2N1/4N3/2RK4 w - -,20,711,14694,528837,11064418,399982579 -8/2r4n/4k3/1P2b1pr/2P4P/p4p2/8/2R1N1K1 w - -,15,521,8037,266372,4428855,142777535 -4k3/2r4B/p4n2/prpP2P1/P7/2N4P/1b1nN3/4KR2 b - -,37,1113,37477,1084586,35450129,1001411469 -bb3N2/8/1k6/7P/P3p3/r7/5K2/8 b - -,28,273,6814,67148,1739312,17462465 -5k2/P6B/P7/1P3r2/7P/8/4N1K1/6B1 b - -,16,401,6101,166628,2550078,72322496 -rqb1k2r/pp1p1p2/2nP4/2p2Ppp/1N2p1P1/1Q5P/PP2PKB1/R3B1NR b kq -,25,882,21141,746925,18534822,660422738 -2b1Rn2/8/7k/r2p1p2/1p3PPp/1P5P/8/2K2n2 w - -,16,365,5433,125808,1842909,43409287 -rnb1kb1r/1p1p1ppp/p1p2n2/1q2p3/P5P1/1P2P3/1BPP1P1P/RN1QKBNR w KQkq -,34,1156,36880,1281512,41147926,1438787000 -k3b3/8/1n6/3p2p1/8/N2p1n2/3K4/8 w - -,5,119,829,18764,151727,3306086 -8/3rk3/2n3n1/5P2/2p5/2N5/1K4B1/3R4 b - -,27,862,20905,612262,14812239,409040225 -r2r4/p1p2kpp/n3b3/P3PNb1/4P3/1PP2PP1/4N1q1/R3K3 b - -,50,909,41339,742625,33881608,609701053 -8/2Pk4/n4b1Q/1r5p/3p3P/6B1/8/2RK4 b - -,29,945,21385,743706,15572660,555269702 -5r2/4k3/8/2K5/5P1p/p5b1/1R6/1B6 w - -,28,609,14195,299642,6850318,148388340 -2r2k2/Np2qr2/N2pb2n/B6Q/P1P2pPp/1P1PPP2/3K3P/4RB1R w - -,43,1405,58963,1965576,81913339,2775504923 -8/5k2/8/3K4/4q3/6B1/8/6Q1 w - -,3,76,1519,31874,717764,15054308 -8/8/2P4k/8/K7/7p/1Q6/8 b - -,5,145,867,22611,146743,3823382 -5k2/pr1R2p1/1p5q/5pn1/P1N1PP1p/1bp4B/1b5P/5K1R b - -,33,1025,34691,995011,35186189,976899639 -rnbqkbnr/pp1p2p1/2p2p1p/4p3/P4B2/1P1P2P1/2P1PP1P/RN1QKBNR b KQkq -,27,733,20301,578559,16530544,487732162 -rnbqkbnr/3ppppp/p1p5/6P1/2p5/3P3B/PP2PP1P/RNBQK1NR b KQkq -,20,579,13048,398946,10033322,319082590 -2b1kbnr/rppqp3/n2p3p/5pp1/p1PP2P1/PP2P2P/1B2QP2/RN2KBNR w KQk -,24,576,15712,417380,12214998,350439421 -2R5/8/3p1P1k/N3n1r1/3K4/8/7p/3b3n b - -,30,627,18506,346645,10280797,190526635 -1R6/k3n3/1q1PK2N/1p5R/1p5P/1P6/8/5r2 b - -,35,682,20692,433677,13053413,281535059 -b4k2/4R2B/1P6/p5P1/P3P3/8/2K2p1b/8 w - -,23,337,6816,117546,2287764,43879287 -rn2qb1r/N1pkpbp1/Qp6/5P1p/2pP1P2/3BP2P/PP1N4/1RB1K2R w - -,37,820,31143,740911,28516079,726154641 -1rk5/8/1p3R2/1P3p1K/P7/3BpN2/1b6/R7 b - -,15,548,8803,301904,5400956,179760904 -6R1/8/6k1/2PP4/K3p3/6p1/8/5rq1 b - -,6,114,2400,39585,987959,15258910 -rnbk4/1p1qbppr/2p1p2n/p2p3p/PP5P/3P3N/2P1PP2/RNBQKB1R w KQ -,29,833,23608,706508,20703324,646996565 -4n1n1/8/B7/Pp1p1P1p/1k2p3/1P4bP/2p1RR2/2K3N1 b - -,23,410,8877,179791,3852140,84272517 -8/2N2r2/8/p1b2P2/P7/8/2K5/6k1 b - -,23,326,7728,94274,2268382,25733665 -8/rppP1r2/pk6/1P2npPp/1K3p2/P4PPb/8/1N2n1N1 b - -,27,356,9885,152966,4235635,72826743 -b7/3q4/R7/p4Brk/2P2P1p/8/8/1K6 w - -,26,870,18594,598996,12554366,402069326 -2N4k/8/N2p4/1p3nPr/P1P4p/1P1P1P2/3Q3P/2K2B1R w - -,38,607,22336,362913,13136631,220907462 -8/8/8/k3pb1N/8/b1P5/2B4p/1K6 w - -,10,238,3078,70356,1038374,23760716 -5Q2/5b2/p2bk2p/P6P/5RP1/8/5K2/R2q4 b - -,33,809,21445,582569,15372375,442310443 -1r2kb1r/4p1pp/2p2p2/p1p2n1n/2PPPP2/6q1/R2K1N1P/1NB2B1R b k -,43,1109,45424,1176891,46587776,1222478357 -1r1r1b2/1p2p2k/1P3ppn/1Pp4p/1n1P1P1P/5b2/3K4/R7 w - -,20,718,11356,401411,6117360,214348651 -8/8/7k/2PK4/8/7p/7p/2R5 w - -,18,159,2635,27183,467810,5485118 -8/2k3P1/P4p2/2p5/PNP4K/3r4/8/3R4 b - -,22,488,7998,185468,2872159,68471621 -7r/6kp/p4n2/pNpPn3/P5P1/2rR3N/1q4BP/2bK3R b - -,53,1193,61687,1413829,70506719,1661724998 -k5N1/5n1p/2b5/P2p4/6n1/3p3K/3q4/6B1 w - -,14,531,7153,264268,3683162,133608595 -3q1bn1/2p1pkp1/rp3P1r/p2p1b1p/2P2PPP/NQ1P3R/PP4B1/R1BK2N1 b - -,38,1330,46936,1704970,58609359,2188270161 -b7/8/1k5r/8/4K1p1/7p/8/8 w - -,6,155,809,20833,113653,2969187 -1rb1kb1r/1p1qppp1/1pn2n2/2p1P2p/2Pp3P/PN1P1PP1/1P2K3/R1B2BNR b k -,27,668,19382,494015,14890234,389490432 -rnbqkbnr/1ppppppp/8/p7/3P4/8/PPPQPPPP/RNB1KBNR b KQkq -,21,608,14236,452342,11549899,389158647 -1n1r4/5R2/7b/2pp1kpn/P1p4r/2K2P1P/6B1/1b6 b - -,4,66,1871,29518,876131,14102315 -r1bqkbnr/pp2pppp/2n5/2pp4/2P5/P6P/1P1PPPP1/RNBQKBNR w KQkq -,20,656,15096,510637,12977723,450355960 -b3k3/n7/5n2/P1p5/2PpPN2/3Pb3/1p4K1/8 b - -,28,355,10175,122479,3532994,39939892 -2bqkbnr/2p1p1p1/rpn2p1p/p2pP3/2P2PPP/8/PP1P4/RNBQKBNR b KQk -,27,827,23042,726240,20912748,678804655 -2n2k2/3bp3/N7/p6P/5P2/1R2K2p/7Q/1r4rn w - -,33,1221,36880,1333039,40261554,1436732774 -4n1n1/8/B7/1p1p1P1p/Pk2p2b/1P5P/2p1R2R/2K3N1 w - -,20,416,8535,177587,3907026,82175776 -rn3bnr/p7/b2ppkpp/5p2/pP1PP3/R2p4/3BNPPP/1N1K3R w - -,34,658,20710,449141,13910222,328210490 -1R6/r2k4/Q5p1/pp1p1p2/Pb3P2/4BqP1/2p3P1/R1K1N3 b - -,28,909,21084,679560,16431398,532808108 -1r6/3r1b2/2p2k1p/P2p2n1/3PpK2/1P6/2B1R2R/B7 w - -,24,783,18908,580039,14831959,443278467 -rnb1k1n1/p3pp1r/1qpp4/1p6/P3P1p1/1P1PN3/2PRN1P1/2K1bBQR b q -,43,1189,49237,1461557,58351228,1814424439 -8/6k1/1P3rP1/pR1B4/8/K7/8/8 w - -,24,407,9510,160515,3722262,60802329 -rnbqk2r/1p1p1pp1/2p1pb1n/p6p/8/P2P3P/1PP1PP2/RNBQKBNR b KQkq -,32,740,24391,590047,19960888,507104817 -5k2/4R1q1/8/8/P3p2r/1p1P4/7K/1r6 w - -,0,0,0,0,0,0 -rnbqkbnr/pppp1ppp/8/4p3/8/P2P4/1PP1PPPP/RNBQKBNR b KQkq -,30,756,23300,606139,19269338,519286744 -8/8/5k2/8/R3n2p/1P6/2K4p/8 w - -,17,311,5256,93762,1580062,27688109 -7k/5R2/6P1/2p2P1P/8/5K2/2b5/8 b - -,9,146,1254,22130,195136,3548411 -8/5k2/7R/2PP4/1K6/4p1p1/8/4r3 b - -,15,322,4949,92733,1502868,26336170 -2bkq2Q/2n1p3/r2p3b/3P2pp/ppP3P1/PP2PN1P/3NKPR1/2R2B2 w - -,39,1032,38687,1086397,39629374,1162027164 -1rkb4/8/1p3R2/1P3p2/B7/3Np2K/P2n4/3R4 w - -,32,487,14976,252118,7646974,141566339 -8/5k2/8/3K4/3Q4/6B1/8/6q1 b - -,18,541,10628,277055,5584564,136981810 -2b1kb1r/1r1p1ppp/ppn2q2/Q1P1pP1P/2P5/4P3/P2PK2n/RNB2BNR b k -,37,987,36109,999796,36344313,1045004645 -5k2/1pr1p2p/7n/3p1Pp1/2PB2b1/6P1/4RN1P/2K2BR1 w - -,40,839,30283,693589,24243149,580102361 -1k2r3/8/PpB3P1/2R5/2P5/6p1/8/3K2N1 b - -,18,417,6250,154529,2260272,57459212 -k7/7p/P1nB4/3p4/b2N4/3p4/1q1n2K1/8 w - -,26,933,18980,653712,12472389,424384329 -2K5/8/8/8/k7/3p4/8/6n1 w - -,5,45,297,3275,19623,237312 -6R1/p1P4k/P7/2P5/4r2K/1P3r2/8/5B2 w - -,3,84,1662,38834,806589,18152911 -1n1qNbr1/1b1kpBp1/2N2n2/2ppP2p/P2P1p2/B1r3P1/5P2/2RQK1R1 b - -,35,1420,44167,1797192,56414128,2310823037 -5B2/3n4/r5k1/K2N1b2/8/6Pp/8/8 w - -,3,75,1256,31139,533260,14162431 -rnk5/pb4r1/2p3p1/1p3p1p/1P2P1P1/1PB2pRP/P2KN3/4RB2 b - -,23,683,15605,483361,11196822,356397524 -3R4/4Nr2/1kr5/1P1n4/6p1/1K6/6p1/8 b - -,40,818,26483,527481,17042884,334213093 -1N2k3/3b2b1/P3p1p1/2BPrPrp/2P4P/8/4R3/n1K4R w - -,41,1019,35333,956656,30755788,883041819 -1nb3nr/2p1p3/r3k3/ppP2pq1/1P1pP1Q1/N5PP/P2bKP2/R1B2BNR w - -,26,949,25775,924987,27022030,958058694 -4N3/3r4/4N2k/p4p2/P1K2P2/8/5b2/8 w - -,14,338,4518,96019,1337308,27098547 -8/1R6/1K3k2/5P2/3r3p/p5b1/8/8 w - -,14,342,5450,129515,1948555,46751505 -1rB3r1/1bN1b2p/p1p3k1/2P1p3/1PR2q2/3p4/PB2P3/3K1RN1 w - -,37,1690,58570,2371850,82956559,3165544869 -b2k4/n7/P7/2p3N1/2PpPb2/3P2K1/1p5n/8 w - -,5,131,1135,26800,244997,6394461 -6k1/8/3R4/4b3/3p4/B5p1/2b3P1/2K5 b - -,20,313,5230,96522,1638895,31509498 -8/5k2/Bnb2r2/4R1bn/P2p2r1/2p5/8/3K4 w - -,24,1032,19905,841984,15585698,649787328 -8/r7/8/1k2N3/p2P4/P5K1/7r/2Rb4 b - -,33,671,18580,375230,10160663,205012981 -6k1/8/6b1/8/1b1B4/6p1/6K1/8 w - -,19,412,5975,126170,1626778,34075016 -7r/k7/6p1/p3p2p/P6P/2rpnP2/5K1R/1R2B3 w - -,19,552,10970,311893,6740664,189467861 -1nb4r/7k/1p1p1p1P/rP1p4/1p1p3N/5BB1/7K/1RR5 b - -,27,923,23923,844245,22484226,801926064 -8/3q3B/R6k/1P3P2/p6p/5b2/8/1K6 b - -,8,141,4197,65327,1978532,31426449 -rnbqkbnr/3ppppp/pp6/2p5/2P3P1/4P3/PP1P1P1P/RNBQKBNR w KQkq -,27,485,13490,286279,8272850,198216986 -r3r3/p2k2B1/P1b5/2PPb1q1/1PB1n3/6P1/1P5P/1N2KR2 w - -,31,1461,40518,1836575,49462518,2183756312 -8/6r1/2kb1B1p/5p1P/P7/n2P4/3KN3/5R2 b - -,35,1070,31449,868881,24123875,627006834 -2k5/7b/8/p7/8/6K1/2r5/8 b - -,24,128,3298,16411,433254,2227125 -1kn5/7P/p5r1/P1pb4/1P6/1PR2B1P/1N1B1K2/r4r2 w - -,2,98,2694,120611,3415136,143613443 -8/2k5/2b5/r2B4/3n2pp/2Q5/8/2K5 w - -,33,907,25425,698430,19403065,525383090 -6k1/8/np6/8/8/5p2/8/3K2n1 w - -,4,52,299,4330,23508,367633 -rnbqkbnr/pppp1ppp/8/4p3/6P1/7B/PPPPPP1P/RNBQK1NR b KQkq -,30,563,17253,361797,11375866,263681542 -rnb1kb1r/pp1pp1pp/1q3p1n/2p5/4PP2/2PP3P/PP4P1/RNBQKBNR b KQkq -,30,891,26586,781504,23879465,708367109 -3rkb2/p1Q1R3/n1n5/3b4/pP1p4/3N1p2/5P1K/BR4n1 b - -,2,73,2015,69238,1952440,65686667 -1r1k3N/1n1b3p/3b1P2/p1ppp1rp/3P1PPP/2p1R3/2K1B2B/8 w - -,32,893,25494,704328,19465564,541370168 -6r1/4k3/3nNn2/8/8/8/1K2B3/8 b - -,33,753,22056,456587,12534678,242412405 -r1bqkb1r/pppppp1p/6pn/4n3/2PP4/3Q4/PP2PPPP/RNB1KBNR b KQkq -,23,841,21206,753041,20317640,711377920 -5k2/1N3r2/p4b2/p1p4n/P7/N4R2/8/5K1N b - -,25,534,11372,246524,5667746,128153671 -8/3Q4/1k6/8/8/3K4/6Q1/5B2 w - -,51,140,6967,16927,829535,2494936 -8/8/3K3B/R3P1P1/5k2/Pp3q2/8/8 b - -,24,364,8357,130289,3015019,49373304 -q1b2bnr/1r5k/p1PN4/3Pp1p1/2P2p1P/N2KPPP1/P3B3/B3R1R1 w - -,36,1260,42486,1436076,49052420,1665973540 -3R4/2k5/3b4/p4B2/2r1p2p/R7/3K1P1P/1r4N1 b - -,37,1097,35279,1025098,31434764,906609161 -8/5B1n/6nR/P4Pb1/kp5p/5R1P/8/1K4N1 w - -,29,454,13645,220126,6673867,111662143 -1r1k4/8/8/2PP2R1/4p3/2K2Pp1/6p1/8 b - -,20,310,6168,97160,1946616,31057512 -8/k2B4/4p3/4P2p/4P2P/8/7N/1K6 w - -,14,66,1016,4997,79983,401420 -4k2r/6pp/2p1pp2/p3PP1n/1bPpq3/2N4N/1rR2KBP/6R1 w - -,28,1125,25963,1026170,25425310,991611684 -1r2n3/4p1n1/2k5/p6p/2B4r/4NK2/1b1B4/1N6 w - -,29,1014,27784,982289,26387689,936559747 -3k2r1/6N1/2n2P2/3p4/8/6b1/7n/3K4 b - -,26,229,5840,60069,1610475,17812804 -8/3k3p/8/rp3Pp1/4r2P/3n1K2/8/4R3 b - -,41,616,22135,335827,11476808,175679212 -2B1k3/7N/Q1r2b2/P2p2P1/R3p2p/N1P4P/4K2R/8 b - -,22,756,14949,546292,10322334,391870340 -5n2/3r2kr/7p/1R1b4/p1p4p/4PBb1/N2RK3/8 w - -,28,954,28443,954383,29421875,981296734 -rnq2b1r/1b2pk2/p2p4/2p2p1p/P2P4/4P1P1/K3NPPR/R2NQB2 b - -,33,841,28268,804716,27418917,840053529 -6r1/2k2n2/2qN4/2PPp3/Q1P3Rp/K4Pp1/8/6R1 b - -,33,1228,33462,1197005,31677869,1115277089 -1r2bkn1/Np5r/N2p1q2/B7/P1P2pQp/3PPP2/1P4PP/3RKB1R b - -,42,1740,64814,2636383,94668530,3807754374 -3r4/1p2pkbp/3p3n/1R3Pp1/2P1p1b1/6PN/3K3P/B4B1R w - -,30,913,26402,789702,23413575,697484732 -6kr/3Pb3/2r3p1/p3p2p/P3PP1P/3Q4/3pK2R/2RN1BN1 b - -,33,1411,39314,1597028,43968445,1757852484 -r1b3nr/3pqp2/4Nk1b/pppP2p1/1nP4p/P4PP1/2QRPK1P/5BNR b - -,28,1003,27842,944516,27551413,911683788 -rn4k1/7q/1pppp3/pR1Q1pp1/P4P2/B4P2/2NK2b1/6N1 w - -,39,1250,47814,1433914,52931359,1561987676 -rnb1k1nr/2pp2p1/1p3p1p/pQb2q2/NP1p1PP1/4B2P/P1P1P3/2R1KBNR w Kkq -,32,1098,36506,1273346,43590661,1535029409 -1R6/8/4k3/r1n4n/1p1p1p1p/1P5P/8/2Kb4 b - -,33,451,13214,172739,4977350,65436418 -7Q/B7/6RP/k7/3P4/8/8/bK6 b - -,6,196,1660,56014,505922,17998567 -2r5/8/5b1k/1p6/2Np2P1/1R4B1/5K2/rN5r w - -,30,1216,33106,1290524,34686893,1319061066 -1n1rkb1r/1p1b4/1q1pp2p/N1p2pp1/1nQ1P2P/P1PP1P2/1P2N1P1/R1BB1K1R w - -,43,1336,57177,1827435,77485100,2540427138 -7k/8/1p6/1n6/8/5n2/1K4b1/8 b - -,20,121,2635,12038,274416,1356787 -r1b1kbr1/p2pp2p/2p1npN1/R6p/1p1PPP2/4B3/K1P1B1PP/7R w q -,49,1300,57474,1532493,64434174,1748480555 -8/6kB/1P6/p5P1/PR6/6b1/1K3p2/8 w - -,25,385,8775,150968,3325068,61765351 -2b2kr1/p7/B2ppn1b/P2rP1N1/6Pp/2R4P/2P5/1N1QBKR1 b - -,27,1079,27983,1109305,29918831,1184379205 -r4b1r/1k2p3/n1p2npp/Pp3b2/5Q2/2PPP1qP/P4P2/RNB1KB2 w Q -,33,1470,44165,1909468,56317737,2375760546 -6br/5k2/2B1n2p/2r5/6K1/1PBpp2R/8/R7 w - -,47,1123,43779,1091664,40459107,1040877752 -6b1/1r2k3/np5N/4P3/P2P1PP1/1P4BK/b7/3B1R2 b - -,22,525,11346,284891,6524526,171171601 -Bnbqk3/2pppp1r/p5p1/1p2b2p/PP5Q/B3P1PP/3PKP2/RN4NR w - -,34,852,29340,741580,25941450,671691077 -4k3/2r4B/p7/prpP2P1/P3n3/1nN3NP/1b6/4KR2 w - -,30,909,25891,778833,21594465,647948037 -1n1B4/rb4b1/1P4k1/pP2p3/2P1P1p1/1N2r1P1/1R4BP/5K1R b - -,28,697,20363,535070,16019750,436462440 -rnb2br1/pp3k1p/4p2n/5pp1/P1p2BPP/2PPN2N/4PP2/R2QKB1R b K -,28,943,26553,941568,27198677,994722470 -7k/rpr1n3/1P2p1p1/5p1p/5b1P/5b2/R2K4/8 w - -,2,80,1156,45698,592263,23022965 -3knb2/p2r4/1P2B3/P1pNp1pP/2P5/R7/8/4KR2 w - -,40,849,32655,636298,23827201,460381704 -1rb1kr2/p1p1p2p/1p2P2b/QnBp1np1/1P3pP1/P2PqP2/1N2N2P/3RK2R b - -,38,858,31164,769020,27867010,739509790 -rnbqkbr1/pp1ppppp/2p4n/7Q/3PP3/8/PPP2PPP/RNB1KBNR w KQq -,49,884,38964,849866,36308268,893197210 -4qk2/5Np1/pp4q1/1R3pn1/P2KPP1p/1b5B/7P/4R3 w - -,34,1347,36867,1427359,38164992,1473950264 -1r3k2/Np2q1r1/N2pb2n/B6Q/P1P2pPp/3PPP2/1P1K3P/4RB1R b - -,36,1561,54545,2326571,82050561,3463302303 -r1bqkbr1/p1pppp1p/6pn/1p2nQ2/2PP4/8/PP2PPPP/RNB1KBNR w KQq -,43,1016,38400,987897,36314506,998762661 -5Nk1/8/3rn3/8/P2P4/KPp2P1p/7P/3Q1B1R b - -,20,510,10380,285465,5737271,166417560 -b2b4/5r2/7k/8/8/2p5/1n2K3/6rn w - -,1,52,109,5408,13669,660204 -5bn1/5r2/3rkp1p/pp5P/P5P1/N1p2P2/3P2BK/2B4R b - -,28,549,15033,319106,8769646,196980635 -8/3n4/8/6b1/k7/1R6/K7/8 w - -,17,256,3994,60824,948774,14909062 -2n1k3/3bp3/N3P1r1/p1r4P/4Q3/3K1P1p/8/3R3n w - -,37,1151,38283,1162780,38243438,1150151441 -1k6/8/P4p2/2p5/PNP5/7K/8/R7 w - -,21,117,2509,13283,286871,1583641 -r1k4r/5pQ1/p2p3b/1pp2pP1/P2R4/7b/1PK4P/1nB2R2 w - -,41,1060,41099,1118099,42738483,1202274829 -1k6/n6P/pr3B2/P1p5/1P5P/1P6/1N2B2r/5K2 w - -,30,628,15880,357166,8948917,210965732 -2B5/2r1b1k1/8/8/4b3/2pp2r1/1n6/4K3 b - -,47,384,17083,149434,6482700,57456686 -3rkbr1/2n1pp1p/5np1/p1P5/pP6/2P4b/3B1P1P/1RNK1BqR b - -,46,810,36363,752382,33259280,756496098 -r3kb1r/4pppp/2p5/p1p4n/q1Pn1P2/R3P2N/3P3P/1NB1KB1R b kq -,33,617,20853,446916,15343266,357915345 -1R6/6Q1/k1B1P3/8/1p4p1/K5b1/3q2P1/8 w - -,3,91,3159,77687,2591799,63551358 -5k2/2R2N2/1p2B3/1P1r4/P7/8/5K1b/b7 w - -,30,815,21489,559196,14712445,381272950 -rnbq1b1r/pp1pp3/2p2pkp/1P4p1/3Pn1Q1/P1NN3P/2P5/R1B1KB1R w KQ -,45,1133,49364,1321777,56675766,1587222402 -8/1b5k/7P/P3P3/6P1/2K1p1B1/8/8 b - -,14,207,2876,42275,586246,8658532 -1N3b2/8/P1R3P1/3Br2k/7P/3p4/K5N1/8 b - -,20,522,10115,278573,5599851,156824892 -7k/8/8/1p6/8/5n2/n7/3K3b w - -,2,32,172,3178,13366,266739 -5k2/8/1P6/pR1B2P1/5r2/8/1K6/8 b - -,17,399,6721,153935,2542596,58448244 -3k4/R7/Pprn4/2p4P/2P1B3/3R2p1/2N5/3K4 b - -,6,222,2450,85507,1175217,39667844 -7k/1b6/1K3R2/2P5/8/7p/8/8 w - -,18,187,3434,38522,693192,8377654 -7k/P7/4pnp1/1p1b1p1p/7P/2r5/3bK3/5R2 w - -,18,688,10702,397564,6237121,225556163 -2n1k1r1/rp3p2/3b1P1R/pPPp2p1/5p2/P1N1N3/2P1P3/B1R1KB2 b - -,23,725,16658,524216,12112343,385035240 -r1b3r1/p1p1k1pp/n2pQ3/PN2P3/4P2b/2P3P1/1P3P2/2R2KNq b - -,4,114,3199,81989,2538855,65513783 -8/rp4k1/1PR1p1p1/3n1p1p/5b1P/2r5/4K1b1/8 b - -,51,521,22955,272382,11356256,145946006 -8/3Pk3/p6Q/P3p3/N1p3B1/8/8/5K1R b - -,4,176,701,30206,135637,5757810 -1k6/8/1R6/4N3/7b/3K4/5b2/8 b - -,5,121,1719,39459,642385,14481305 -2b1kbn1/4p1rp/2p3p1/Pr1PP3/2PB4/6P1/p4PBP/R1N1K2R w KQ -,34,966,32043,876472,28732455,786208585 -2b1rb2/3k3r/n4BPp/1RP1p2P/2p1p3/N4N2/P2P4/1R2K3 b - -,22,794,17639,628858,14987310,532972134 -rB2kbnr/pb6/1p6/3p1p1p/PpP3Pq/1Q5N/3PPP1P/RN2KB1R b KQkq -,34,1213,43008,1538359,56636332,2042428250 -4Nk2/8/B5P1/1P6/b6B/p7/8/5KR1 b - -,7,143,1334,30545,323406,8086939 -2k4r/p2n1p2/1pp1p2b/1n5p/2B2rP1/2P4b/PP5K/2R3NR b - -,42,976,41023,986328,41210239,1018871765 -1r5r/5bk1/2nP4/pP3pp1/P2R1PPQ/b3PR2/5K2/8 b - -,45,1313,49122,1445231,52629219,1562542505 -rnbqkbnr/pp4p1/3pp2p/5p1P/2p5/NP5N/P1PPPPP1/1RBQKB1R w Kkq -,21,623,14633,434395,11185633,336230787 -8/1B6/2q1k3/1p6/3p4/1p6/8/3K4 b - -,29,239,5525,53185,1275362,13275339 -2R5/6p1/7k/6P1/b2K4/8/2q2n2/8 b - -,4,66,1986,24573,772317,9576923 -2r3nr/2N1kp1p/p1b1p1pb/7P/2p1PqP1/5P2/P2P1K1R/RQB5 w - -,33,1304,40336,1554006,49854585,1890776890 -4r2r/4p3/b4P1k/2p2P2/R5pP/4b1PN/6K1/1q5R w - -,26,1214,25750,1132776,25481402,1086215863 -1B1k2n1/6b1/2r3pq/4Rp1r/pPN2P1P/2P3n1/1R6/3K4 b - -,29,967,27127,856910,25705613,779953946 -1n5k/1b2p1r1/1B4p1/1P1p1p1p/2p2PPP/1p2P3/3b2KN/1N2RR2 b - -,26,677,17528,469013,12262113,339762673 -r1bqkbnr/pppppp2/8/6pp/3n1P2/2P4P/PP1NP1P1/R1BQKBNR b KQkq -,30,696,20885,547442,16579877,477298284 -2r4r/1ppk3p/3b1p1n/Q1B2n2/PP3P2/2p1p1Pq/3RP2P/4KbR1 w - -,25,834,20353,706975,17952910,639132346 -rn2qb1r/N1pkp1pp/Qp6/3bnP2/2pP1P2/4P2P/PP1NB3/R1B1K1R1 w Q -,45,1457,61279,1916981,79775362,2487489850 -k7/3N4/1R6/1Kn3p1/8/2pp4/7P/8 w - -,21,205,4535,44458,963705,10666298 -r1n1k1r1/2b2p2/2p2P2/pP1p2p1/5p1R/P1N1N3/1BP1P3/2R1KB2 b - -,27,882,23226,745578,19339953,620223402 -8/p2pkNr1/b2b3p/3p1P1P/1rB3p1/P1n3R1/Q1PK2P1/1R4N1 w - -,41,1408,50677,1725768,60737131,2051637621 -8/6k1/4P3/8/P3P3/7N/N7/5K2 b - -,7,105,455,7220,36284,612987 -8/7k/3RP3/8/4n2p/8/8/3BK3 b - -,14,269,3279,69212,787984,17440110 -5k2/5B2/3BP2R/5P2/1p5K/8/8/2n5 b - -,1,26,144,3549,22643,546586 -r1bnk1n1/p7/q2p3P/2p1pp1p/pPPN1pP1/3P3R/4PP2/R1QK1B2 b q -,31,1187,37765,1407813,45620115,1674518519 -1n3R2/3k4/3r3b/2pp2pn/P1p2P2/7r/1K6/1b3B2 w - -,20,659,12294,407948,7749029,258029463 -2b4k/8/2Pp1r2/p1N1Qp2/Pr3PPp/1P5P/3K1n2/R5n1 b - -,30,988,28201,903611,25928263,814291554 -3krb2/2p1p3/4b2r/pN3pP1/pqPp4/3P1P1P/PB3RB1/2K3NR w - -,26,786,17487,552853,12876454,415209773 -r1bq1b2/p4kp1/1p1pp2r/1Pp1P1pp/P1K2P1P/7R/2P1PB2/RNnQ1BN1 b - -,30,1078,32360,1143051,34362552,1202982912 -8/8/4k3/7B/1p1p4/8/8/7K b - -,9,90,762,8933,74705,922228 -rnb4r/4b2k/1R1pP3/4N2P/pP2nP1P/p1N5/3B4/1K5R b - -,32,1119,35883,1241435,39939235,1371082859 -Q7/3P4/p3k3/P1n1p3/P1p5/2N1bK2/8/3R1B2 w - -,42,649,25674,410263,15952442,249676180 -8/8/8/1PK5/8/6N1/6k1/8 w - -,14,86,1128,5446,69168,383233 -4N1k1/5b2/B3R3/6P1/1P6/p5B1/5K2/7R w - -,53,369,17434,183209,8140912,92635914 -2r5/1k6/1B6/5Ppp/PR5P/2q5/6K1/R7 b - -,40,1150,35641,999451,31072046,865972276 -1r2kqr1/p1B5/4pnp1/2p2B1p/P1b1Pp1P/1P3P2/1R1P4/2BKR3 b - -,36,877,30574,779909,27485935,731751544 -8/3k4/4R3/2PP4/1K2p3/5Pp1/4r1p1/8 b - -,16,327,5476,100882,1850653,32077599 -1r2kbn1/p3qbp1/n1pp1p1r/P3Q2p/Rp2P2P/1P1P2P1/2P2P2/1N2KBNR w K -,39,1063,38792,1121380,39683218,1203436463 -2r5/k4Nr1/5P2/8/2p1K3/2P5/8/4N3 w - -,18,437,6968,165221,2585316,61197764 -1B6/5Rb1/2r1k1p1/5pnr/pP5P/2P1NK2/4n3/2R5 w - -,4,125,4502,137632,4698549,145170321 -8/5n2/k2P4/1p6/1p4KP/1PNR1R2/8/r7 w - -,29,601,16310,310371,8665988,161305006 -rnbq3r/p2p3k/1pp2p2/1PbNp1pp/3PnN1Q/P6P/2PB4/2R1KB1R b K -,36,1374,46805,1812459,61259518,2394173342 -rnb3nr/2p1p1b1/p3k1qQ/1pPp1p2/8/N3P2P/PP1P1PP1/R1B1KBNR w KQ -,33,915,30346,896972,29698234,905819376 -4b3/1k6/8/p3r3/8/6K1/8/8 w - -,8,224,1093,29994,155444,4218274 -B1k5/3r4/P4r2/PP6/7P/8/4N2K/6B1 b - -,31,722,19274,465826,11707337,288026149 -k2r3r/5p2/p2p3b/Ppp1QpP1/3R4/R6b/1P2K2P/2B5 w - -,50,1216,51348,1265450,50416919,1271030969 -7b/2r4n/4k3/1P4pr/2P2p1P/p7/8/3RN1K1 b - -,30,636,18167,377699,10774027,221195619 -2k3r1/6n1/1n6/8/2K5/8/8/8 w - -,7,126,767,16685,95925,2305445 -1rk5/7p/2bR3P/3p4/p7/1pb2Kp1/8/8 b - -,27,344,7937,105535,2538718,36054133 -2k1N3/6b1/2b5/2B5/8/8/4K3/7r w - -,19,645,10586,343615,5570094,175271772 -B4B2/3r1r2/p3Nbkp/PP6/4P3/2Rp4/8/4K3 w - -,34,866,24508,668275,18523905,518588597 -b4r2/8/3R4/p4B1k/q1P2P1p/8/2K5/8 w - -,6,174,3836,109122,2288860,67481103 -2b2bn1/rpppqp1r/3kp1p1/p6p/1nP5/P2P1P2/R2NP1PP/2Q1KBNR w K -,26,783,19661,591189,15537656,471610063 -b4b1n/3k2rR/P1pB1P2/8/p1Pp1pP1/N5P1/3RB3/1N3K2 w - -,38,665,24740,497134,18373658,382195984 -2b2bn1/3kp1rp/1Bp3p1/Pr1PP3/2P5/6P1/p3KPBP/R1N4R b - -,20,683,13956,467170,10548948,349855066 -rqb1kN2/5N2/3P4/pp3P2/4p1rp/P3Q2P/1P1BPKB1/R6R b - -,23,1086,27942,1263295,35312352,1558200638 -1k1b4/7r/p2p3Q/Ppp2pP1/3R1B2/3K3b/RP5r/8 w - -,31,955,28652,854153,26375685,778041911 -8/2p5/rp4P1/1pk2p1p/4bP2/4n3/3N1K2/8 w - -,12,324,3394,92495,988752,26826597 -8/3n4/k7/2R5/1K6/2p5/7P/3b4 w - -,17,254,4350,67361,1159032,18823111 -r1bqkb1r/ppppp1pp/2n4n/4Pp2/8/5P2/PPPP2PP/RNBQKBNR w KQkq -,26,542,14490,323037,8827612,209254694 -1nq3nr/3k3p/1p2p1p1/r2b4/PB3bP1/2Q2P1P/3pPKB1/5RNR b - -,48,1518,65787,2032584,89347215,2738084317 -1rb1k1r1/p3p1Bp/1N2P3/1npN2p1/QP4P1/P2P1P2/4n1KP/3R3R b - -,24,980,23021,949864,23538518,980273261 -1n1R4/4k3/5r2/2p3bn/P2p3r/2p5/4B3/1b1K4 w - -,20,788,14469,559281,10153827,390606941 -6n1/2p1k2r/P1r4p/P2p1ppq/1n1P1P1P/1P1bP3/3KR3/RBBN4 w - -,20,857,17415,713914,15374450,614856095 -rnbqkb1r/pBpppp2/1p3np1/7p/8/2P1P3/PP1P1PPP/RNBQK1NR b KQkq -,24,794,20369,678214,18408249,616473108 -Nb4n1/4B1qr/1p5k/5Ppp/1pP3PN/p4R1P/P3B3/R2K4 b - -,25,690,17898,500496,13800201,392058519 -r7/2p3r1/P2k1nPp/P2p4/3Pp1bP/1P1nKR2/BB6/5R2 w - -,24,956,23555,897191,22391525,817750581 -8/p3k3/P7/1N1p4/3P3p/6qP/8/B2K4 b - -,29,262,6471,63172,1422585,14745087 -6n1/2pr3r/P2k2Pp/P2p4/1n1Pp1bP/BP2K3/B7/1R3qR1 w - -,19,716,12552,434865,8448946,282844138 -b2N4/n1k5/P7/2p5/2PpPK1b/3P4/1p5n/8 b - -,27,187,4539,37626,973132,8596300 -8/6B1/1K6/R3P1P1/P4k2/3b4/4q3/8 w - -,17,539,9013,282625,4927040,151652625 -1n6/3k4/8/4R2K/4PQ2/8/8/8 w - -,30,177,5851,37583,1269230,9324704 -rnbqkbr1/pppp1ppp/8/4p3/P2PPB2/3Q4/1PP2PPP/RN2KnNR w KQq -,44,1421,57831,1904130,74966717,2514384342 -8/7k/4P3/8/P3P3/7N/N7/5K2 w - -,15,74,1187,5387,91909,439279 -rnbqkbnr/pppppp1p/6p1/8/2P5/8/PPQPPPPP/RNB1KBNR b KQkq -,21,589,13630,407090,10272819,318951653 -4kr2/pb5N/B2pp2b/P3r3/6Pp/NR5P/2P2B2/3Q1KR1 w - -,39,1391,51087,1693920,64824224,2060956903 -r4b1r/2qb2k1/pp2p3/1PpQp2p/P1K1BP1P/5N2/2P1P2B/RNn5 w - -,36,1121,38148,1172284,40392209,1249136571 -k7/b6P/b7/6N1/8/r7/3Kp3/8 b - -,29,302,8022,94615,2676195,34409389 -8/5k2/2K5/8/1q6/6B1/8/6Q1 b - -,31,650,15274,350775,7679346,182753187 -1r2k1n1/p2p2p1/1p4N1/2r2p2/2b2PPp/b1pQq3/P2BP2P/R2K1B1R b - -,50,1422,63678,1863274,82348852,2471810829 -r1q4r/pbpk1pbp/3p3n/Pp2p3/2QPP3/4B1PN/1PP1BP1P/nN1K3R w - -,44,1275,54418,1642806,68093567,2127158985 -1N6/4k3/2K5/1p2P3/2N4P/R1P2p2/1r6/8 b - -,18,417,6749,159567,2552281,60978708 -b1k5/b7/2P1r2N/7P/P3p3/2K5/8/8 b - -,21,232,5195,61533,1410657,16913293 -4k3/K3N3/p6r/p7/P7/1N6/8/8 b - -,18,271,4574,67167,1092386,15826675 -1r2rbk1/np2p3/1p3pp1/Pqp4p/1P5P/3PnPPb/1R2B3/2K2R2 w - -,19,818,16244,690430,14189011,601420216 -k5N1/2B2n1p/P1b5/2qp4/6n1/3p3K/8/8 w - -,17,654,10036,370361,5560781,200185177 -1r3bn1/4pk1r/3Q1p1p/pp5P/Pp6/2N2PP1/1R1P2B1/1NB2RK1 b - -,18,720,11634,458486,7637981,300952873 -2b1kb1r/r5pp/p1n2p2/2PppP1P/Q1p1P2R/N4K2/PB1P4/R4nN1 w k -,37,1097,37736,1165214,40903798,1290148644 -rnbqkbnr/p1pppppp/1p6/8/2P3P1/8/PP1PPP1P/RNBQKBNR b KQkq -,21,485,11099,282565,7040837,193961515 -8/4k3/3p1N1n/1B6/3qp3/5n2/4K3/8 b - -,36,476,15071,198568,6321887,84598499 -1rb1qbn1/ppppprp1/8/P4Pk1/P1P3Pp/B6P/RQ1P1K1N/1N4R1 b - -,18,663,12903,474610,10423737,381313083 -rr6/p1p2kp1/n3b2p/P3PNb1/4P3/1PP2PP1/2K1N1q1/1R6 b - -,44,932,38469,826913,34875817,755037319 -4kb2/1b2p1rp/1Bp2np1/Pr1PP3/2P5/1N4PB/p3KP1P/3R3R b - -,28,1243,34719,1409082,40348880,1532779586 -4N3/1B2k1B1/8/1p2p3/1P2QP1r/p1R5/b4K2/1N5R w - -,62,1196,65340,1257132,67199402,1287957086 -1n1Qk3/r4N2/P2P1q2/R4P1p/1P6/2Rp1PK1/8/5B1q b - -,2,71,2057,49028,1516802,37535619 -rnNk4/4r2b/1p6/5Qp1/1b1PPPPp/PP2BN2/b6K/3B3R w - -,40,1266,50350,1544295,61379317,1861882964 -6N1/5n2/3p4/1B3kn1/4p3/8/1q6/3K4 w - -,13,382,4186,117054,1385389,38870398 -6nr/6kp/p7/pNpPn3/P5P1/2rR4/1q2KNBP/2b4R w - -,4,162,4042,164412,4017891,163854318 -8/r2k4/Pp1n4/2p4P/2P5/3R1Np1/8/3K3B b - -,13,304,5290,130649,2423319,60914788 -3k1N2/8/8/1P6/7P/pK2R3/5n2/8 w - -,25,215,5135,47414,1073458,11013390 -b4rn1/p3k3/q2pn2P/2P1pp2/p1P1NpPp/Q2PR3/2K1PP2/R4B2 w - -,36,1280,43912,1598746,55160111,2028946504 -b3nbr1/k4Bp1/q3p3/3p3p/P2P4/2K2nQ1/6R1/8 b - -,37,1003,35250,997382,35791220,1013430989 -rn2kb1r/2pqpp1p/4b1p1/pp1p4/1P1Pn1P1/P1P2Q2/3NNP1P/R1B1KB1R b q -,31,936,28899,937482,30198688,1022360289 -4B2k/8/P2BP1R1/1pn2P1K/8/8/8/8 w - -,29,257,7783,60000,1715394,12835859 -3Q4/4p2k/Nn6/p1K2P1P/8/7p/1R1r4/1r1b3n w - -,32,1016,28470,901728,25617379,816571012 -7k/8/5N2/2P5/B7/8/K7/8 w - -,21,35,660,3467,65068,283258 -3nrb1r/pppk3p/3pqp1n/2P1p3/P2P4/BPQ3Pb/4PPBP/RN2K2R b K -,33,1269,42229,1556399,53589418,1934343247 -1rbqkbnr/pppppppp/8/2n5/8/4P2Q/PPPP1PPP/RNB1KBNR w KQk -,34,786,26974,650517,23002439,585609336 -7k/8/1p3n1P/1P1p3b/6RK/3b1B2/3pr3/8 w - -,22,707,13857,450550,8614319,283889017 -r2k1b1r/1p2qp2/1n1p2pp/pPp1pP2/3P1n1P/2N2Q2/PBPNP3/3RKB1R b - -,40,1581,60823,2380512,88684894,3482406648 -2b2r1k/1r1p4/N7/p1P2p2/P4PPp/1P1n3P/N2K4/1RQ3n1 b - -,29,697,19408,488836,14187324,379136912 -2b2bn1/1k4b1/3p4/3P1Pp1/p1P3Pp/4K2P/4R3/1B1NN1R1 w - -,29,615,17316,385647,10752347,245181172 -1n2rk2/7p/rpb1p3/p4N2/P1P1pP1p/8/1b2PKB1/3R2nR b - -,33,1057,34555,1029368,33613146,972019951 -1rbq1bn1/2pkp3/n2p3p/3P1pp1/ppP3P1/PPBQP2P/3N1P2/R3KBNR b KQ -,20,718,15726,568525,13492527,492282858 -rnbqk2r/pppp2pp/4pb1n/5p2/2P5/1P2P3/P1QP1PPP/1RB1KBNR b Kkq -,32,957,30990,951179,31185502,978896203 -b7/2b5/4K3/3r3k/8/2p5/1n6/2r4n w - -,3,126,628,27098,112909,4954279 -1n3B1r/5b1k/1p3p1P/1P1p2R1/1p1p3N/5B2/7K/3r4 w - -,30,652,17132,403679,10496904,261909784 -1n1r2kr/8/2b4p/pR6/2p4p/2b1Pp2/2N5/5RKB b - -,37,1076,37536,1015965,35035483,935900989 -8/7p/2k4P/8/8/5q2/1r6/4b1K1 w - -,0,0,0,0,0,0 -1n1K4/8/2k5/2p5/2b4B/3p4/8/8 w - -,9,142,1422,22988,242447,4127561 -2N2k2/4qr2/N2pQ2n/Bp6/P1P3Pp/1P1PpP2/3K3P/4RB1R w - -,8,215,9289,240457,10516431,277001282 -8/4k3/3NB3/2P5/8/8/8/1K6 b - -,4,89,331,6576,33182,641205 -6k1/3Pb3/2r3pr/p3p2p/P4P1P/3QP3/3p3R/2RNKBN1 w - -,5,163,7021,184339,7889262,196748097 -7k/8/3R3P/3B1bn1/5K2/3b4/8/8 w - -,26,570,13582,298143,7005992,148158573 -8/6k1/4P3/P3P3/8/3N4/6K1/6N1 b - -,6,114,507,9174,43936,788469 -rnbq1b1r/pp1ppk2/2p2p1p/6p1/1P1PP1Q1/P1NN3P/2P2n2/R1B1KB1R b KQ -,29,1228,34781,1453528,42319574,1756093477 -2k4q/2P3b1/4b3/1p1pP3/1p2rr2/4B2B/6P1/4Kn2 w - -,7,227,2279,83063,1058901,40811469 -3k4/2r5/8/8/N1p2P1n/1n5B/1K6/4R2b b - -,28,808,21980,584667,16137542,412954839 -k7/8/4P3/5Q2/3b4/8/6P1/3K1B2 w - -,34,455,14647,156576,4965450,52441363 -6nr/1pq1bk2/8/5Ppp/ppN1p1P1/B1P4P/P2pK1B1/3R2NR w - -,29,986,26806,950621,25512331,923708818 -rnbqk2r/1ppp1pbp/4p1pn/p7/2PPP1P1/7N/PP1K1PBP/RNBQR3 b kq -,31,997,31778,1064479,34755070,1193557098 -r2qkb1r/p2bp1pp/npp2p2/3p1n2/2B2P2/N1P1P1PP/PP1P4/R1BQK1NR w KQkq -,31,859,26829,787298,24789873,759699431 -6n1/1k6/1b6/2pbbP2/2RR2Pp/p3K2P/8/1B1N4 b - -,34,781,24865,626245,18862068,491380646 -r2qkbnr/1bppp2p/1p4p1/p4p2/P1Pn4/3BPP2/1P1B2PP/RN1QK1NR w KQkq -,31,1084,33167,1139047,36288287,1247022165 -8/8/1k1Np3/4P2p/K1B1P2P/8/8/8 b - -,4,77,306,5536,23284,405894 -rn6/p3k2p/2pb1r2/rB2Bp2/6PP/8/1P3P1R/2K3R1 w - -,33,982,31686,963366,31087909,965744171 -rnbqkbnr/1p1ppp1p/8/p5p1/PPp2PP1/3P4/2P1P2P/RNBQKBNR w KQkq -,27,640,17682,464985,13251267,377939172 -5nR1/8/8/6b1/k7/8/K7/8 w - -,8,117,1539,22073,331424,4932162 -rn3bnr/8/p2ppk1p/1b1P1pp1/pP2P3/3R4/3KNPPP/1N2B2R b - -,25,792,20201,619077,16312889,488456684 -3k4/3r4/6n1/5P2/N1pn2B1/8/1K6/3R3b b - -,35,853,26825,647040,19968227,482013741 -4N3/8/8/p4P2/Pb1r4/4K3/6k1/8 b - -,26,180,4318,35700,827569,7596030 -r3k1n1/p2p2p1/1prb2N1/5pq1/2bp1PPp/2pQ4/P3PB1P/RN2KB1R b KQq -,43,1544,64627,2258812,95387294,3327067414 -5k2/6R1/1p2B2N/1P2b3/P7/5K2/8/b2r4 b - -,29,939,24231,682744,17461022,463165085 -3n4/3rk3/8/5P2/2p4n/2N5/6B1/1K1R4 w - -,32,596,16109,343513,9027064,201230317 -8/k7/8/1K1B4/7b/1r4p1/8/8 w - -,6,105,1369,27141,327589,6943893 -7k/rp2B3/n7/2bpp3/P4r1N/1p4PK/7P/RN6 b - -,35,648,19066,401858,11963081,274981070 -r1bqkbnr/1pppp1pp/2n5/p4p2/2PP4/4P3/PP3PPP/RNBQKBNR b KQkq -,23,760,18400,594770,15652187,507963492 -8/2kB4/3b4/8/2P1p3/2K5/6N1/8 b - -,15,246,3728,62176,876278,14756640 -1r2bb1r/1Bn3k1/p2p3R/P1p2p1q/3P1p2/PK4p1/3B4/RQ4N1 b - -,38,1165,42121,1442131,51956083,1884482030 -5r2/p4r2/1Q6/q3pk1p/PB3pp1/1PnPP2N/1RK2PP1/1N3B1R w - -,41,1356,53762,1834477,69678895,2424831066 -r1b1kbnr/pp2p1pp/n6q/2p2P2/NPPp1P2/P2P3P/4PK2/R1BQ1BNR w kq -,26,752,19474,590210,15985917,501415235 -5N2/4k3/2Bp4/3q1Pb1/4p1nR/8/4n3/5K1n w - -,23,826,16509,588925,11707125,415038210 -5k2/8/8/r2n1pP1/1p1p3p/1P1b2nP/2R5/1K6 b - -,34,169,5498,67785,2138020,27175710 -6k1/5n2/5B1B/5P2/8/2K2p2/8/8 w - -,23,195,4151,36984,781200,7821714 -1r1k1bnr/pp1b1pp1/B2p1q1p/2p1p2Q/P3P1P1/2PP3P/1P1K4/RNB3NR b - -,34,865,28483,791347,25742977,760097849 -rnbqkbnr/pp1ppp2/2p4p/6B1/8/1P1P4/P1P1PPPP/RN1QKBNR w KQkq -,30,595,17125,398912,11592527,301579199 -1n4k1/8/7p/Pp1p3P/P2pPN1B/4RR2/b4PP1/3K4 b - -,16,439,6552,182136,2718857,77424105 -4k1B1/8/2p1pbpr/ppP1P1Bp/PP1Q4/3RKP1P/6P1/1N4R1 b - -,13,537,6368,271719,3456146,149439174 -8/2k5/2b5/3B4/P2n2pp/2Q5/4r3/2K5 b - -,29,858,23559,653453,17579856,479343727 -8/8/6kp/1n6/3P2p1/2QK4/2P5/1R4n1 w - -,28,465,13606,206933,6247526,91189956 -1r6/k7/8/1P6/6p1/8/8/K2r2n1 w - -,2,58,298,7794,43230,1186326 -r1b3n1/ppp4r/1k1p1p1b/5Qpp/4PpnP/NPq2PPR/P3K3/4RBN1 b - -,42,1046,39206,1003922,38219167,1020463489 -3nk3/3N4/B7/8/P2r4/1P3P1p/K1p3RP/8 b - -,25,662,15387,385038,9128236,222491098 -1B1k2nb/2r5/3q2p1/N2R1p1r/pP5P/2P5/8/2RK3n w - -,19,549,11903,381715,9186417,318143149 -2b1kb2/r3p1rp/2p2Bpn/P2P4/1pPqP3/N5P1/P4P1P/R1N1KB1R b KQ -,45,1148,48991,1310436,53454178,1481457078 -5B1r/3n3k/1p2bpRP/1P1p1N2/1p6/3p4/6BK/8 w - -,28,395,10387,174369,4564257,85855517 -4r3/q4r2/5k2/p3p3/PB1Q2pp/1PnPpP1N/1RKN2P1/5B1R b - -,45,1665,60577,2166254,78077692,2776446317 -6br/4bk2/1pq1pnp1/p6p/P2p1PPP/1Q4N1/1P4BR/RN2BK2 w - -,43,1662,66084,2432283,98442812,3521525008 -3rkb2/1q1b4/3pp2r/1pp5/2P3np/nP1P4/4N1P1/1RBB1KR1 b - -,39,700,27571,565643,22591540,504602847 -b6n/6b1/P1pBkP2/8/p1P3P1/3p2p1/2N1B3/1N1R1K2 b - -,16,443,7546,204832,3703613,101017529 -3N3Q/2nk4/8/7p/3B3P/1rR5/8/3K4 b - -,18,663,10817,400883,6430327,243020845 -rnNk2b1/6r1/1p2q3/6pp/Qb1PPP2/P3BN1P/1P3K2/1b1B1R2 w - -,41,2107,85695,4186042,169493574,7999907421 -r2n1r2/1bNk2pp/6P1/pP3p2/Q2pP2P/1P1PBR1q/2P3p1/4K1N1 w - -,39,1222,44683,1415044,51039263,1643061120 -b4b1n/3k2rR/P1pr4/2B2Pp1/p1PppQP1/N5P1/R2PB3/1N3K2 w - -,36,689,26382,547518,21496720,473381090 -8/8/2k1b3/4b1P1/2P5/1p4p1/1N2K3/N6R b - -,26,645,15578,344951,8050374,172903453 -8/QR6/5kp1/p2p1p2/p4P2/R3B1P1/4K1P1/4b3 b - -,8,306,2359,93685,797075,32254323 -Q7/q2bb1k1/pp2p3/PPp1P2p/3nBB1P/3KP3/6N1/4rN2 w - -,32,915,25803,774598,21809122,671591547 -8/2k5/7P/4P3/3K4/1N6/8/8 b - -,7,95,539,7764,41695,611651 -1r1k2nN/7B/3p3b/2qPp3/5R1p/3n1PR1/4K3/8 b - -,48,1228,51479,1226096,50164368,1189648147 -1r2nb2/4p3/8/p2k1n1p/P1p4r/2Qpp3/1B1NB1K1/RN6 w - -,32,932,28964,862898,27151019,818058943 -rk6/2p1r3/5pp1/p2PpP1p/P1P1PqP1/4Q2B/1P1K2R1/RNB5 b - -,27,687,17916,512707,13543496,405619510 -8/p3k3/P7/K2p4/3P3p/2N5/6q1/B7 b - -,28,315,7794,77193,1880372,19814267 -k7/b7/5b1R/4N3/8/1K6/8/8 b - -,16,416,7132,172263,2990496,70224590 -5k2/8/np6/8/8/4Kp2/3b4/6n1 w - -,5,100,487,10010,50468,1067627 -r1b5/ppp1nr2/1k1p1p1b/4PQpp/5pnP/NP1K1PPR/Pq4B1/4R1N1 b - -,45,1280,54879,1577379,65988601,1917677611 -1N6/8/4Q3/2k5/3pbr2/2NP3K/4Q3/1R6 b - -,21,1055,16436,820135,12738454,623813339 -3b1r2/5k2/6p1/p3p2p/P3PPBP/Q7/3p1K1R/1RrN2N1 w - -,50,1133,48747,1170976,48483480,1215600693 -q1b2bnr/r3pk2/p2p2p1/1NPP1p1B/2P4P/N3P1P1/P2K1P2/R1B3R1 w - -,31,783,23684,642093,19618497,564601199 -r1b5/1pp3r1/pk1p1pnb/4P1Qp/1P3pnP/N2K1PP1/Pq4B1/4R1NR b - -,46,1162,51074,1328473,57332876,1539176461 -2K2k2/8/p1N5/p7/P7/8/5N2/5r2 b - -,12,208,3352,51490,840892,12672219 -5N2/8/b1Np4/q7/5k2/6R1/1K3n2/8 w - -,30,913,19542,596047,12778226,385986885 -b3nbr1/1q2pBp1/1k6/3p3p/P2P4/3K1n2/6Q1/6R1 b - -,29,892,25384,809651,24300963,765593048 -8/7R/1K6/6q1/P5k1/3b4/8/2B5 w - -,25,776,15104,448417,8819050,262184785 -rnb2bnr/ppppkpp1/4p2p/8/P1PPP3/1P4q1/3K1PPP/RNBQ1BNR w - -,31,1089,30973,1032281,31214114,1016200790 -8/3k4/8/Rp1KP3/1N5P/1pP2p2/3N4/8 b - -,7,186,1419,37988,334964,8816427 -6k1/8/8/1p4n1/1n6/8/2K5/7b w - -,7,168,777,18583,86930,2088372 -4N3/1B2k1B1/1p2b3/4p3/1P2QP1r/p1R5/8/1N4KR b - -,27,1327,30523,1503468,32879728,1630957215 -7k/7B/P7/5K2/1p3b2/2r4p/4N3/8 w - -,15,382,5819,133346,2155858,48578637 -2k2Nr1/5n2/5n2/8/8/8/1KB5/8 b - -,26,495,12279,219203,5408679,93539872 -5N1k/4Qn2/1N1p4/2r5/P1BP3p/KPp2P2/7P/7R b - -,20,937,15242,675779,10655118,455598619 -3r4/p2n1k2/2R5/n7/pP1p1K1b/5p2/1N3P2/B5n1 w - -,23,717,13750,429394,8105679,251917593 -rb4b1/r7/1p6/pNP1P3/Pp6/3kp2P/3P3R/3K4 w - -,17,401,6786,170907,3055105,81322968 -8/3P1k2/pQ5b/P3p3/n1p3B1/2N5/8/5K1R w - -,52,744,35556,508232,23313756,330841380 -8/3k4/K7/8/1N1b3P/5p2/7r/8 b - -,31,285,7923,82950,2116989,22131554 -r3k2r/1b1Bb2p/p1p3pB/3Np3/1PPp4/5q2/P2KP3/RQ4NR b kq -,3,134,5846,225469,8852526,342044036 -2b5/r5r1/1p4N1/p1k1bp2/PpPpP3/R2Q1q1P/3P4/1N2KBR1 w - -,27,1237,30597,1331284,35125268,1461599143 -1r4k1/1b6/1NQ3p1/1P1p1p2/Pp3PnP/3pR3/4PNB1/2R1K3 b - -,25,1253,27685,1330913,29421234,1371684395 -2r1k1n1/5b2/p2p4/P3p3/R1p1PP1p/2K2Q1N/B5P1/3N2R1 w - -,30,581,18802,383953,12965256,276191744 -2r3nr/q3p3/6Bk/1bp1P3/6pP/6P1/3b1P1K/R5NR b - -,42,1133,45899,1188864,47655295,1228716661 -7k/3n1n2/7B/5P2/7B/2K2p2/8/8 b - -,14,296,4036,79511,1148316,22192454 -1N6/6P1/6k1/r2b4/2Np2K1/3P4/8/QR6 b - -,25,880,20190,722533,15756157,578676150 -r7/1p6/p1kb1Q2/2p1Pbrp/R1K2pnP/1PP2P2/4N3/1N1R4 w - -,40,1164,38323,1103266,35833843,1025039590 -rnbqkb1r/pp1pp2p/2p2n2/3B1pp1/P3P3/5P1P/1PPPN1PR/RNBQK3 b Q -,26,812,21626,666910,18700463,579449439 -2kNQr2/8/4n3/7p/5B1P/1K1R4/8/8 b - -,14,539,7015,277690,3880475,150366829 -rnbqkbnr/p1pppppp/1p6/8/7P/P7/1PPPPPP1/RNBQKBNR b KQkq -,21,420,9700,219822,5547801,139328782 -rn1q1b1r/pkp2ppp/1p2pn2/3p4/2P1PP1P/6P1/PP1PbNB1/RNBQK2R w KQ -,30,1261,39168,1614692,51491112,2089803988 -8/7B/8/kp5R/2P5/8/6p1/2K1N3 w - -,29,232,6380,69444,1819042,24159485 -B1k2b2/p4r2/1P3p1n/P1p1p1NP/2P2N2/R7/8/4K2R b - -,21,859,17680,696792,14255832,550607405 -4b3/3n2kp/3b4/B1pNn3/P1PpPr2/1p1P4/6K1/1R6 w - -,29,1064,27731,963437,23768171,807743131 -2R5/p1q5/nkB1PQ2/8/1P4p1/2P5/2KR2P1/6b1 b - -,25,1181,27807,1266843,30439836,1347931849 -8/4rr2/1q3k2/p3p3/P2Q3p/1PnPppPN/1RKN2B1/7R b - -,41,1614,56616,2105288,74901981,2730585307 -5k2/2B5/6rr/1p1ppK2/8/Rn4P1/1p4N1/1N4b1 w - -,22,782,17013,622484,14164651,520743358 -2k2q2/2P2rb1/2r5/1p1ppb2/1p1P2n1/8/5BPR/3BK3 b - -,46,1000,44644,988428,43744967,983199533 -1b5q/3B4/1k6/8/2P1pN2/1K6/8/8 b - -,31,656,18160,342342,9440766,164576855 -2r1k3/8/1N6/8/2pB1P1n/7B/1K6/n3R2b b - -,4,167,3503,130387,2985925,105417427 -8/5k2/8/1p4n1/1n6/8/8/2K4b b - -,26,105,2742,13702,357264,1622691 -2k5/1n6/8/4Q2p/5r1P/5R2/2K5/8 b - -,18,759,11564,425290,6769882,232831904 -5R1r/k4N2/5P1r/8/2p5/2P3K1/8/4N3 w - -,22,296,5790,101606,2114664,41102918 -k4b2/4Q3/8/2p3NP/2bp4/P1P2KP1/1rN2P1R/8 w - -,41,956,34865,800379,28344267,653086791 -1rbq4/p2p2p1/P1p1p3/1pPn1Pk1/P6p/B6P/R2PR2b/1NQ1K3 b - -,39,1017,34011,931393,30224343,870307892 -rnbqkb1r/ppp1p1pp/3p1p1n/8/8/N7/PPPPPPPP/R1BQKBNR w KQkq -,20,558,12470,343589,8509441,237353305 -8/8/P4n2/1k6/1pR4n/1B5P/7R/3K2N1 w - -,32,456,14817,203583,6581054,93018538 -8/3k1p1p/3b2r1/p3p1R1/1P1r4/pRPNB2b/3K1PBP/8 b - -,38,1190,42661,1460407,51583230,1839162707 -2n5/1r1B4/5p1p/3k2rP/P5R1/3P1N2/3B2K1/4b3 w - -,30,779,23489,613181,18693976,491602200 -8/8/1k6/1p6/1K6/4n1p1/5r2/8 w - -,3,93,300,8304,32597,877956 -6k1/5b1r/3n4/pP6/P4pP1/1R2PR2/2B2K2/2b5 b - -,30,662,20346,471638,14557200,348658710 -2k5/K3R3/2N5/8/7P/5p2/4r3/2b5 w - -,22,419,8304,151000,2969069,56135585 -3n4/5k2/8/3r1PR1/2p4n/2N5/8/1K3B2 w - -,26,535,12785,277469,6669853,148150996 -k7/8/5P1N/7P/2pNb1K1/2P1p3/4rPR1/8 w - -,23,469,10458,206449,4742871,97745564 -6R1/6p1/8/4K1k1/b3n3/8/8/2q5 b - -,39,384,13489,160121,5730194,69847232 -8/8/r2N4/4k3/8/1P2KP1p/7P/8 w - -,14,195,2493,37794,471723,7368554 -2bk1b2/r3r2p/p1n2pp1/2PppP1P/Q1p1P3/NR6/P2P1B2/3R1KN1 w - -,44,1395,59658,1797989,76025996,2233883909 -1B3k1r/6r1/8/1p1ppK2/4n3/6P1/Rp1N2N1/6b1 b - -,45,1019,42497,1010455,40610868,985580943 -8/5rP1/1k3q2/4R3/6K1/6Bp/8/8 b - -,29,521,16031,339993,10764751,244554593 -r1bqkb2/p1pppprp/6pn/1p2n3/2PP2Q1/N7/PP2PPPP/R1B1KBNR b KQq -,24,807,20422,693880,18651257,638283936 -4N3/8/1b2N3/p2r1p1k/P4P2/2K5/8/8 w - -,15,259,3563,66194,919506,17649349 -1B6/3n1k2/8/5P1P/2K2n2/R3Bp2/8/7r b - -,32,951,27525,808397,21856385,635125521 -4r3/1R5p/7P/3K1k1P/2p4n/5p2/8/8 b - -,22,379,7796,126188,2600598,41308249 -5N2/b1R2B2/P5Pk/8/3p4/7P/4p3/2K1N3 w - -,30,208,6201,56914,1623740,17920576 -3r4/5bk1/2nP3r/pP3pp1/P4PP1/b2RPRK1/8/8 b - -,48,795,35497,661557,28026296,571479055 -r4nk1/p5bp/2p5/5p1P/6P1/4R1B1/K7/8 b - -,23,604,14618,371944,9265328,228235106 -8/4k2N/2Bp1b1n/8/3qp3/8/4K2n/8 w - -,12,409,4432,153235,1785823,62188140 -rn4r1/p2Np2p/2p1k3/rBb2p2/5B1P/8/1P3PPR/4K1R1 w - -,37,1126,37095,1126717,36282734,1117797899 -rnk5/1b1p2b1/1P6/pP2p1pr/2PpPP2/B5Pp/3N3P/1R2KB1R b - -,24,680,16614,467547,11671281,333094969 -8/3n4/K5k1/2BN4/8/6Pp/2b5/8 b - -,21,446,8663,172553,3344964,64335164 -BN1R4/8/6k1/4r1P1/2B5/8/K7/3bN3 b - -,25,871,18362,626375,12784711,432233327 -2r5/1bkn2r1/p1p3P1/1p5P/PP1N3R/1P5P/3BK1B1/1r6 b - -,35,945,30375,831425,27356120,762901033 -r1b1kbnr/1p1p3p/6p1/pqp2p2/2P1PB2/P4N2/n2QKPPP/R4B1R b kq -,33,1378,45107,1790696,59177879,2263802486 -8/8/8/1kb1R3/7n/1K6/8/8 b - -,8,133,2121,37187,642635,11261080 -5N2/2k3r1/3N4/n7/3p4/8/K2n4/8 b - -,27,394,9029,121904,2985100,39631660 -7k/5b1B/3n4/pP6/P4pP1/1R2PR1r/5K2/2b5 w - -,25,747,16385,477524,10772419,311303567 -3r4/3k4/3N3n/QbP1p3/2PPqp1p/5PP1/1K2R3/R7 w - -,52,1664,73587,2381671,100355765,3250934860 -8/1pp5/R5P1/1pk2p1p/5Pb1/r3n3/8/1N2K1N1 w - -,19,478,8309,207292,3752992,92237184 -k1r5/8/8/8/3PK3/P6R/4N3/8 w - -,27,417,9565,142993,3186342,47918720 -1b5r/6kp/2b4P/p2pp1r1/B1pP1Pp1/2p5/3R3B/3K4 b - -,6,126,3174,64823,1664469,34371600 -6nQ/3k1p1p/N3p1pb/2r4P/2p1PqP1/B4P2/P1bP1K1R/R7 w - -,37,1577,54363,2159564,75644935,2901137172 -r1n1k1rR/2b2p2/2p2P2/pP4p1/3p4/P1N1p3/1BP1P3/2R1KB2 w - -,24,602,14235,352468,8575662,212056566 -kr1b4/8/1p3R2/1P3p2/B3p3/6K1/PN2R3/1n6 w - -,30,375,9715,162039,4293070,83113833 -1n6/8/1p1kN3/8/1K3P2/1pp5/8/8 w - -,14,145,1679,18981,206719,2534888 -8/P6B/2r4k/6N1/1p4K1/7p/8/8 w - -,22,346,7433,118675,2668294,42833518 -r1b1kb2/3ppprp/pqp3pn/1p2n3/2PPP3/NP3Q2/P4PPP/R1B1KBNR b KQq -,30,1055,32013,1126311,35294964,1248546551 -3N3Q/2nk4/8/2R4p/1r1p3P/8/5B2/3K4 w - -,37,601,21346,333989,11915710,189577544 -rnb2bnr/p1p1k3/4p1pp/1p1p1p2/PPPPP3/R2B2Q1/3K1PPP/1NB3NR b - -,27,1092,27639,1125496,29211556,1192895271 -n1kq4/8/3p3b/1rNP1bp1/pPP1PPPp/7P/p1N1K1B1/R5R1 w - -,39,1231,43211,1394054,46113152,1527707936 -rnbqkbnr/p1pppppp/1p6/8/8/N1P5/PP1PPPPP/R1BQKBNR b KQkq -,21,483,11075,281870,6996150,194065920 -3Q4/1k2Nr2/8/Pp6/8/1p5K/1b2r3/8 b - -,33,749,18692,450571,12306339,300679948 -3b3r/5k2/2r3p1/p3p2p/P3PP1P/3Q4/3pK2R/2RN1BN1 w - -,43,1357,53500,1555494,59392668,1660499359 -1rB3nr/q3p3/6Bk/1bp1P3/6pP/6P1/3b1P1K/5RNR w - -,28,1072,29615,1170122,32433595,1309400682 -3k4/N2r4/7P/1P1n2p1/8/K5p1/8/4r3 b - -,35,261,8089,68491,2120030,19771454 -r1b1kb1r/p1qp1ppp/5n2/1pp5/Pn1p1BP1/8/RPPKPP1P/1N1Q1BNR w kq -,30,1161,34596,1331750,41069648,1581517265 -1r1k1b2/p3pn1R/n7/3b4/pPQpp3/B2N1N2/5Pp1/1R4K1 b - -,28,1291,36031,1601201,45777182,1986216085 -r1bk1b1r/1p1ppP1p/p5pn/q2p4/n4PP1/P1PK3B/1PNQ3P/RNB4R w - -,25,648,16151,454423,12477010,371732932 -1rb1q1r1/3p1pk1/1N6/p7/PnP2pPp/1P1PP3/1R1K1B1P/1QN3n1 w - -,24,854,20127,736776,18317100,690520083 -6b1/4k1PR/8/1P3B2/3B4/8/5K2/n7 w - -,35,439,15641,194368,6922380,91424112 -r6r/2k1p1Bp/1n4pb/pP2p1P1/1P3PBP/P2p2R1/6q1/RNB1K3 w - -,32,1447,39280,1646903,46134370,1836869724 -6kr/3Pb3/4r1p1/p2Qp2p/5P1P/P1p1P3/3B3R/R2NKBN1 w - -,51,1048,47124,1043995,46920162,1116780210 -5r2/p6r/1p3k2/q3p2p/PB3pp1/1PnPQ2N/1R1KPPP1/1N3B1R w - -,31,1133,33454,1191780,36482906,1282575317 -r2n3r/1bp3pp/1N1k2Pn/pP3p2/1b1ppq1P/BP3P1R/2PPPK2/1Q2RBN1 w - -,27,979,23124,875724,21832529,845477564 -8/8/4P1k1/3K4/5B2/4q3/8/8 w - -,13,342,3688,90899,1040062,25212510 -5k2/r4b2/np5N/P3PP2/3P2P1/6BK/b1B5/5R2 b - -,27,835,22925,687865,18883834,562674157 -r4k1B/p1b5/PRP5/2P4r/B1N5/5KP1/1P5P/2q5 w - -,30,1191,29422,1145789,27752830,1061948470 -k7/8/P7/2p5/PNP2p2/7K/8/2R5 w - -,20,73,1450,6399,130642,653105 -8/1B1q2Q1/k3P3/8/1R4p1/K5b1/6P1/8 b - -,3,116,2847,94163,2273841,72018470 -1k6/5N2/3R4/2b1b3/8/1K3N2/8/8 w - -,31,725,21138,443048,12466839,244580266 -r2q1b1r/pkp2ppp/1pn1pn2/3P4/4PPNP/6P1/PP1Pb1B1/RNBQK2R b KQ -,48,1549,71094,2311992,104010608,3435844451 -r1bqk1n1/p2pbpp1/npr5/2p1p3/1P1P1NPp/5P1B/P1P1P2P/RNBQK2R w KQq -,35,1099,38353,1173039,40776258,1246096720 -k5nr/r7/8/np1PN1Pp/1p1Pq2P/1P3N2/5K2/6RR b - -,35,761,28048,651465,24333392,581902518 -1r3br1/1bN4p/p1p1B1k1/4pq2/1PP4R/3p4/PB2P3/3K1RN1 w - -,44,1436,58592,1951699,78121848,2627338454 -8/8/4N3/1p6/2k5/8/4K3/8 b - -,5,77,527,6993,45719,571364 -1n2k3/r1Q1bp2/b2p3p/RPP1NP2/1P6/2Rp1Pr1/5KBq/3q4 b - -,47,1272,50136,1367973,54903943,1518682164 -r2qkbnr/1pn1pp1p/3p4/5Pp1/P1p3b1/1p1P3B/1BP1P2P/RN1QK1NR w Kkq -,30,1019,30885,1081786,33705422,1208180210 -rnbr4/1pppqk2/1b2p3/pP3pp1/P2PP1np/3Q1P1K/1BPN2PP/1R3BNR b - -,37,951,35039,971596,35437733,1035540207 -2b1rb2/2nk3P/7p/1RP1B2P/2p1p3/N4N2/PR1P4/4K3 b - -,22,831,18902,705175,16642613,620354425 -6k1/8/4P3/8/4K3/5p2/8/4B3 b - -,5,78,482,7240,52138,745340 -4kb2/5p1p/2P2nr1/p3p1R1/1P1r4/pRPN3b/3B1PBP/3K4 b - -,41,1430,54680,1843854,68544931,2300682582 -r1b5/1pp2nr1/pk1p1p2/4P1bp/1P3p1P/N2KnPP1/P1R5/5BNR w - -,34,1066,31830,1018632,29282850,960854646 -r1bqk1n1/p2p1pp1/nprb4/3Np3/3P2Pp/2p1BP1B/P3P2P/RN1QK2R w KQq -,35,1075,38037,1211094,43107262,1409319379 -2k5/P1P3b1/2N1p1p1/3P2rp/R4B1P/3b4/2nK3R/1r6 w - -,34,1410,45523,1720360,55337999,1970609319 -1rb1k1r1/p2p2b1/B3p3/6pn/P2P2Pp/2p4P/R1P1P3/1N1QBKNR b - -,28,719,20881,568849,16817129,482069455 -2n5/1r1B4/3k1p1p/6rP/P5R1/3P4/3B1bK1/4N3 b - -,40,1047,35379,1021024,32490486,962110372 -r7/1kb4Q/p2B2P1/Ppp2p2/3Rr3/RP5b/3K4/8 b - -,30,1005,28908,989580,28233059,978814493 -2r5/1kb5/p5P1/PppR1p2/2r2B2/RP5b/3Q4/4K3 w - -,39,1166,42344,1260034,45761079,1353356072 -1B6/4Bnk1/4n3/5P2/8/2K2p2/1r6/8 b - -,32,616,15621,291861,7261814,135167709 -5b2/7k/4P3/3Q3p/P3P2P/3N4/N5K1/8 b - -,12,447,4679,167361,1788635,62015304 -1r6/3r1b2/2B2k1p/P1pp2n1/3P1K1R/1P2p3/6R1/B7 w - -,31,1033,29487,926743,26516964,813193465 -5B2/3n4/6k1/8/K7/2N3Pp/2b5/3r4 w - -,4,124,2162,65182,1081585,32028986 -8/r7/1R6/2k5/p4K2/Pb1P4/2N4r/8 w - -,26,725,15685,431799,8749482,239630160 -K7/8/1P6/8/7k/8/8/8 b - -,5,20,136,816,5502,37912 -2b5/6k1/6n1/1r3pP1/1p1p1P1p/1P5P/1K6/4Rn2 b - -,26,436,10842,155516,3898417,53102562 -3rk3/1q1b2b1/4p2r/1ppp4/B1P3np/3PB3/4N1P1/1R3KR1 b - -,41,1183,48140,1333706,54321267,1494703958 -2N4R/8/p5k1/pN6/P1p5/4K1N1/8/1n6 b - -,9,291,2615,78602,730304,21274485 -2k5/7r/4K3/8/3P4/P6N/5R2/8 w - -,24,358,7380,110496,2238439,33931298 -4kbr1/rp3p2/1n5R/pPPp1Pp1/2N2p2/P1N5/2P1P3/BR2KB2 b - -,24,972,22526,859943,20391737,755733810 -r1Nk2b1/3n2r1/1p2q3/6pp/Qb1PPP2/P3BN1P/1Pp1K3/1R1B1R2 b - -,62,2375,133479,5070327,266193901,10101110190 -5k2/8/1Pr3P1/pR6/4B3/K7/8/8 b - -,17,433,6913,166295,2612727,61960161 -2n5/8/K3N1kB/8/b5p1/6PR/r7/8 b - -,25,389,8977,165398,3942374,81855696 -7k/8/3n4/4K2p/8/1P5p/7R/8 w - -,16,190,3100,34336,597358,6742053 -8/4k3/Bn3r2/2R3bn/P2pb1r1/2p5/8/3K4 b - -,54,1029,47728,856037,38212708,687890128 -n2k4/8/8/1P1P1Q2/3Pn2P/2p1K2R/8/1N6 w - -,32,354,11235,134828,4091776,51715253 -8/8/3k2r1/1p6/r1nK2p1/5R2/8/8 w - -,17,455,5524,160404,2131945,64028917 -2R5/p1k5/n1pqP2Q/1pb5/1P4p1/2P5/2KRB1P1/8 b - -,3,123,3026,117449,3090148,121172691 -rnbqkbnr/ppp1pppp/8/3p4/P7/4P3/1PPP1PPP/RNBQKBNR b KQkq -,28,863,24559,769381,22972388,734258706 -6n1/8/Bb3n2/1pkp1P1p/P3p3/1Pp4P/2R4R/3K2N1 b - -,19,482,9358,232951,4747403,118896427 -4B1r1/k1n5/8/p3p3/3r2p1/8/1b2K3/3N2B1 w - -,19,517,9304,272068,4960837,151460167 -8/P7/3Rn3/2k5/1p6/7P/2B1N1K1/5nR1 w - -,36,501,16978,229796,8425178,113580173 -6n1/b1k5/8/4bP2/R2p2Pp/p2B3P/b3K3/3N4 w - -,24,599,14581,360665,8848786,219891232 -8/8/4k3/r6n/1R3pbp/1n1p3P/8/1K6 b - -,36,417,11984,155261,4462689,59384331 -5r2/1Qb3k1/6p1/p3p2p/P3PP1P/2r4B/3p1K1R/1R1N2N1 w - -,38,1185,43591,1272067,48312439,1350799868 -b1N1k1r1/8/8/5np1/pBp2P2/4p1P1/Kb6/R4BR1 w - -,28,930,27332,885454,27002079,864342786 -5k2/1Q6/8/p2p1p2/R4p2/5bP1/3B2P1/4bK2 w - -,40,463,15471,201589,6653824,92787026 -8/8/8/4P2P/2k1N3/8/8/5K2 b - -,6,89,566,7851,46974,643018 -N7/4kn2/4b3/PP1p3P/5pB1/1p1P2R1/6K1/7N b - -,20,413,8098,169255,3199537,69294138 -rn1q1b1r/p1p1pppp/1pk2n2/3p4/2P1PP1P/6PN/PP1Pb1B1/RNBQK2R b KQ -,36,1040,34010,1022100,33445171,1036785011 -rnbqkbnr/pp1ppppp/8/2p5/1P6/P7/2PPPPPP/RNBQKBNR b KQkq -,23,458,11543,259281,7087832,176404262 -3r3r/2k2p2/p2p3b/Ppp1QpP1/3R4/n6b/1P1K3P/2B2R2 w - -,44,1246,47301,1336107,49051836,1394973783 -8/8/8/5kN1/8/1P1K1P1p/7P/6r1 b - -,16,196,2963,34194,525008,6053302 -1k6/5b2/2n5/3p2p1/8/N2K4/8/8 b - -,19,160,2927,28545,518325,5146765 -r4br1/8/3k1npp/P1n1p3/8/2PPP1qP/4bPB1/RNB1K3 w Q -,24,1155,26440,1218982,27780951,1246603688 -8/q7/2P2P2/8/p4k1p/K7/8/8 w - -,5,126,848,21218,161906,3936799 -3rk3/6b1/1q2b2r/1pPpp3/Bp1P2np/7R/4N1P1/5KB1 b - -,39,936,36904,848525,34188112,802994381 -rnbqkb1r/pppppppp/5n2/8/4P3/2P5/PP1P1PPP/RNBQKBNR b KQkq -,22,679,16065,501702,12689916,404129911 -bRkq4/7p/2P5/P1np4/2Nr2n1/3p3K/3P4/2B5 b - -,2,33,1093,17985,595545,10082339 -1k3br1/8/1p3p2/pP2p3/B3n3/2R5/P1R2N1K/8 w - -,26,638,16254,409937,10878359,275057604 -1r2kb1r/p2bp3/2qp1ppn/1pP4p/2PPN2P/N3P1P1/P4P2/R1B1KBR1 b Q -,38,992,35361,973239,35188503,1000726034 -Rn5Q/p1k5/2ppp3/1pqPP3/1P4p1/2P5/3RBbP1/2K5 w - -,40,814,30362,648095,23397953,520910806 -8/8/2P1qP2/8/p5kp/8/8/1K6 b - -,28,149,4302,26321,710414,5307970 -8/8/8/3k4/4b3/6K1/8/4n3 b - -,20,110,2306,10487,216268,1024404 -1r1r1bk1/np2p3/1P3ppn/1Pp4p/R4P1P/3P1b2/1R1K4/5q2 w - -,21,941,15888,709036,12368546,547981557 -rnbqkbnr/ppppppp1/7p/8/8/3P2P1/PPP1PP1P/RNBQKBNR b KQkq -,19,531,11436,326113,7873344,230435644 -6n1/1k6/8/b1pbbP2/2R3Pp/p3K2P/6R1/1B1N4 w - -,30,1115,29174,1018724,26075468,863847861 -r4bbr/3kB3/1p3q2/p4p1P/PpPp4/2Q2N2/3PPPBP/RN2K2R w KQ -,37,1394,52523,1941947,73701340,2707464086 -4k1r1/1b1n4/1B1bn3/1p1r2p1/p1p2P1p/P3p1P1/3N1N2/R1K2BR1 b - -,48,1577,73423,2347640,106549923,3386748453 -8/1K3n2/6k1/8/8/8/8/8 w - -,8,104,555,6786,41130,489716 -k7/8/7P/rb6/8/4b3/4p2N/4K3 b - -,27,112,3397,23064,682485,5700042 -3N1B1k/Bn5P/8/1b6/3K2p1/2r3P1/7R/8 w - -,30,714,19120,428570,11377513,250979398 -8/p3k3/n5R1/4K3/3p4/5p2/3b4/6n1 w - -,18,346,5621,109073,1702533,33653890 -1rbk1br1/pR1pp2p/n1p2pN1/7p/1p1PPP1P/8/2P1BBP1/1K5R b - -,20,823,17908,694478,16269487,603569805 -5n2/8/8/8/k4b2/8/K7/6R1 b - -,18,295,4873,74797,1226753,19243986 -rnb1k1n1/p3pp1r/1qpp4/1p4p1/P1N1P3/1P1P4/2P1N1P1/2KRbBQR w q -,36,1692,58936,2572000,90295785,3738507500 -8/3kb2r/7p/Bn3p1P/P4N2/3P4/4K3/5R2 b - -,22,577,12798,335079,7658320,200827963 -3Q4/4p2k/Nn1r1P2/p1K4P/8/7p/R7/1r1b3n b - -,36,878,29443,753974,25707716,687392133 -5rnr/1q2pk2/R7/2p1P3/4BPpP/3bb1P1/6K1/6NR b - -,45,1126,44914,1129389,45124428,1170838454 -1r1k4/3q2r1/p3pnpB/7p/P1p1P2P/1P3P1B/R2PK3/2B1R3 w - -,30,1216,35450,1398495,41864838,1612276941 -1r1r1bn1/1p2p2k/1P3pp1/1Ppb3p/1n1P1P1P/8/R2K4/8 w - -,17,560,9383,309114,4848443,158948577 -8/8/4P2k/8/P3P3/7N/N5K1/8 b - -,4,68,355,6000,27013,466018 -8/8/2bQ4/1k6/6pp/8/r7/2K5 w - -,25,560,11979,254555,5455485,113078497 -6k1/8/8/1p6/1n6/8/2b4n/2K5 w - -,2,44,216,4807,16595,362771 -6k1/rp6/nb3B1r/P2pp1K1/8/1p4P1/7P/RN2N3 b - -,27,527,14687,314442,9022442,206676072 -2b3N1/8/3p4/8/3N1k2/8/3K4/3R4 b - -,13,310,3933,98343,1240102,31955715 -8/1Pk5/8/2P2p1p/3B4/8/4N3/7K b - -,7,152,994,21648,139772,3064669 -1nq3nr/3k3p/bp2p1pb/r1p2p2/P1p1N1P1/BQ3P1P/3PPKB1/5RNR b - -,32,1130,34531,1192914,38100296,1309400937 -8/8/4P1k1/4K3/7B/5p2/8/8 b - -,5,71,411,5834,39747,563965 -rnbqkbnr/p1pppppp/8/1p6/8/N6P/PPPPPPP1/R1BQKBNR b KQkq -,21,398,9232,198000,5007618,119922878 -1k6/8/P7/2p2p2/PNP5/7K/8/R7 b - -,6,115,633,12683,71514,1463402 -1r6/8/1k6/8/3P1K2/P6R/1N6/6r1 b - -,29,644,16441,346341,8942754,186177701 -1b2Q3/5b2/6r1/2P4P/3k4/r7/4pK2/8 b - -,51,994,34157,666227,22254444,440794576 -5k2/2R5/1p2B2N/1P6/P7/3r1K2/7b/b7 w - -,5,140,4142,106557,2876805,74064498 -4qbn1/2p1pkpb/rp3P1r/p2P3p/5PPP/1Q1P3R/PP4B1/RNB1K1N1 b - -,30,1130,33886,1298981,40029766,1549660793 -8/r3n2k/1NQ1p3/p4p2/Pp1N1Pp1/7b/5K2/8 b - -,20,668,13386,421679,8599101,261241331 -8/1B3n1n/1R6/P2p1Pbp/1p6/1k5P/5R2/1K4N1 b - -,22,661,12708,385158,7368033,224131992 -1n3r2/1k3p2/1p5b/pPp1p3/B5K1/2n3R1/PN6/2R5 w - -,28,823,23223,668152,19204948,550864418 -3kN3/1B4BQ/5R2/1p2p1P1/1P6/p5R1/8/1b4K1 w - -,57,617,31716,351989,17451622,197260135 -6kr/1n4n1/8/8/2p5/2N5/6R1/1K3B2 b - -,14,389,7095,186894,3752558,96418330 -8/8/k7/7R/N2p1bPP/3K4/6b1/8 b - -,22,376,6889,126337,2301021,43722772 -rnbqkb1r/1pp1pppp/5n2/p2p4/3PP3/8/PPPN1PPP/R1BQKBNR w KQkq -,32,966,31637,975038,32893725,1046624144 -rk1r4/2p2p2/6p1/p2PpP1p/P1P1P1Pq/3Q3B/1P2KR2/RNB5 b - -,26,979,25810,938340,25501592,910831145 -8/p3k3/P7/1p1p4/3P1q1p/2N4P/4K3/B7 w - -,11,304,2837,70889,714127,16798618 -2bqkr2/1p1p1p1p/r1n4b/pQP1pPp1/3p4/2N2P1N/PP2K1BP/R1B1R3 w - -,41,983,39814,1001678,40841291,1080719250 -1r1k3N/1n1b2rp/3b4/p1pppP1p/1p1P1PPP/2P4R/4B2B/1K6 w - -,28,861,23243,716051,19209840,589761298 -7k/8/1pb2n1P/1P1B2Kb/8/8/6R1/8 b - -,21,464,9286,212693,4202735,94720948 -8/nR5B/r1k2b2/P3p1pp/6bP/2PPP3/8/B3KN2 b - -,22,579,12243,318916,7127386,186298595 -1rbk1bnr/pp3pp1/n2p1q1p/2p1p2Q/P1B1P3/2PP3P/1P1K2P1/RNB3NR w - -,36,1063,34810,1062454,35291483,1113512036 -5k2/8/P5P1/3p2N1/2Q3B1/4p1pP/4K3/2R1N3 w - -,44,261,11423,67155,2850477,17505574 -rN6/5k2/3P4/pp6/3KB1Pp/P7/1P1BP3/R7 w - -,45,528,22092,258684,10176856,128422117 -3n4/b4k2/p7/P2Pp3/P1p4Q/2N2K2/8/4RB2 w - -,43,622,24323,360851,13596037,204652557 -7R/1N6/3p1P1k/8/1K4n1/r4b2/7p/7n b - -,2,42,1172,21542,633252,11677251 -8/k7/2K5/8/8/b7/4B3/6b1 w - -,13,204,2477,43418,532330,9746838 -2kr1brn/1b6/2p1p2p/P1Bp1Pp1/p5P1/N1P2QP1/R2PB3/1N4KR b - -,20,836,18345,779969,18126167,774952047 -5b2/r1B5/nP4k1/NP2P3/2P3p1/3bK1P1/1r4BP/1R5R w - -,36,1322,43353,1531420,49563267,1712343648 -8/r7/4N3/p4P2/Pb6/8/4K3/6k1 w - -,13,255,3009,61142,710359,14901138 -8/p6k/P1P5/2P2r2/1R4rK/8/1P2B3/8 w - -,4,78,1597,29672,607150,11473438 -3r4/7r/1q3k2/p3p3/PP1Q3p/2nPppPN/1RKN2B1/1R6 b - -,54,2201,97281,3835695,164009993,6368039864 -b4N2/1k6/7P/8/P4b2/r3p3/6K1/8 b - -,22,186,4388,38143,926713,8680410 -r1bqkbnr/pp1p1ppp/n1p5/4p3/4PP2/P7/1PPP2PP/RNBQKBNR w KQkq -,29,948,27551,885371,26661862,860893506 -3r1bk1/1p2p2p/3p3n/1R4p1/2P1pPb1/6PN/3K3P/B4B1R b - -,24,791,18974,606574,15119751,481383985 -1k3B1r/7p/1r2p2P/R4Bp1/1P2pP1P/2Np3K/8/2B1R3 b - -,18,785,14877,629622,12694456,524458131 -r1br4/2k3p1/6p1/pP3p2/1Q1nP2P/1P1P2R1/2P1N3/4K1n1 w - -,34,895,27829,750360,23299508,638897846 -rn3bnr/1kq1p3/2pQ2pp/Pp6/8/N1PPPb1P/P4P2/R1B1KB2 b Q -,32,983,29665,924296,28997034,911965560 -r1b1k1n1/3q1pr1/n1p1p2B/1pbp4/Pp2P2P/N1PP1P1B/8/R2QK2R w KQ -,39,1610,61176,2514237,96852143,3979849263 -8/1b6/1k6/8/3K2p1/7p/8/2r5 w - -,3,96,506,15063,73888,2130975 -4n3/4p3/8/p2kbn1p/P1p1N2r/1r1pp3/1B4K1/RN3B2 w - -,22,819,17263,642287,13903812,509708897 -q1r3n1/p7/P2p1R2/1pP2Ppk/1B1Pb2p/7P/1RQ2N2/6K1 b - -,26,895,22239,803780,21162814,787965811 -bn5r/3k3p/2p5/p1Pp2q1/P5n1/2Np3R/3P4/2B3nK w - -,20,738,12648,457705,7655715,274004412 -3k4/4qrb1/2P4r/1p1ppb2/Bp1PN1n1/8/6PR/5KB1 w - -,24,1038,22391,935521,21164231,880457442 -4R3/7k/5n1p/8/1Q1P2p1/1n2K1p1/2P5/6R1 b - -,16,644,9290,360400,5151793,197508506 -2b2b1r/r1p1k2p/p1n1p3/1p4PP/2Pp1K2/PN1n4/1P2B3/RQ4N1 w - -,6,164,4731,129823,3955087,109278621 -7R/8/8/2BN4/4kP2/r6p/4KR2/6b1 b - -,18,585,9479,304989,5167652,165190524 -1rbqkbr1/p2p2pn/1p2p3/2n4p/PP1P4/2p3PP/2P1P3/RNBQKBNR w K -,27,830,22509,709534,20255751,654485304 -8/7k/4P3/7p/P3P2b/7N/N7/6K1 b - -,12,151,1852,26036,327107,4933332 -rnb2qnr/pppPbk1p/4p1p1/5p2/8/1P2PP2/PR1P2PP/2BQKBNR b K -,31,936,29500,895759,28804663,891320588 -4B3/8/7B/4P1P1/pK2k3/PP5q/8/6R1 b - -,27,664,13928,323989,6747677,153660634 -2k1nr2/8/7n/7B/1K6/8/8/8 b - -,22,305,6550,86562,1917187,24999761 -6Q1/3b4/5k2/8/3p1p2/p2Rb1P1/6P1/2B1K3 w - -,34,540,16555,264675,8098907,131414798 -1rb5/5k2/1NQ3pn/pP1p1p2/P4P1P/3pR3/3BP3/2RK1BN1 w - -,46,591,25669,389578,16934266,279836975 -2b2b1r/r1p4p/p1nkp3/1p4PP/2Pp4/PN1Q1K2/1P2B3/R5N1 b - -,22,757,16648,579260,13161795,464269445 -rn1qkbnr/p3ppp1/1ppp2Qp/3B4/6b1/2P4P/PP1PPP2/RNB1K1NR b KQkq -,25,976,23465,872551,21984216,798306998 -8/8/1kb5/r7/3Q2pp/8/B7/2K5 b - -,5,160,3362,106162,2242341,67492905 -5N2/k7/8/1P6/7P/2K3R1/p4n2/8 b - -,14,259,3627,75022,1125984,23290434 -6k1/8/4P3/8/P3P3/7N/N7/6K1 w - -,14,55,853,3944,65361,296144 -2k4r/n2r4/p7/PP1BB3/1P5P/8/4N2K/8 b - -,21,753,16708,535355,12562823,369088932 -8/p1q5/P7/3Pk3/N6p/1K6/8/2B5 w - -,16,351,4988,110308,1638627,35353217 -r1b1kbnr/p2p1ppp/2p1p3/1p2n3/1PN1P3/2N4P/P1PP1KP1/R1BQ1B1R b kq -,29,951,27262,905779,26269162,887451216 -6b1/r5Q1/np1k3N/8/P2PPPP1/1P5p/b4B1K/3BR3 w - -,39,656,24337,444961,16288183,312926455 -1nk5/r4N1b/1p6/6Q1/3PPPPp/PP6/b4B1K/3Bb2R b - -,29,1109,27830,1026348,26037923,948263453 -1n3k2/5n1p/2b5/2p2N2/P1PpP3/1pBP3K/7b/4R3 w - -,29,808,21382,569247,14578329,379444412 -B7/3k3P/6PB/4P3/1K6/8/2b5/8 w - -,26,337,8913,105795,2825368,32384980 -8/3k2R1/8/2PP4/2K1p3/5Pp1/5rp1/8 b - -,3,63,918,17198,286153,5074801 -3r4/8/1k6/8/4K1p1/8/8/1r6 b - -,34,145,4813,26923,880526,4808707 -rn1qkb1r/3b3p/ppp1pp2/1N1p1np1/2B2P2/1PPPP1PP/P7/R1BQ1KNR w kq -,32,985,30754,945464,30435269,952193460 -8/8/3K2k1/4n3/8/8/8/8 b - -,15,87,1168,7341,91777,564537 -8/8/r6b/P2np3/2k3pp/2P1P3/1KB1b3/B4N2 w - -,17,443,7038,187436,2928081,80196329 -4k3/K3N3/p7/p7/P6r/8/8/N7 w - -,13,239,3079,51916,676391,11250797 -r1bqk2r/p1p1pn1p/Qpn4b/1B1pPpp1/NP4P1/5P2/P1PP3P/R1BK2NR b k -,20,611,13713,440500,11008139,364269894 -4k3/N4n2/PPpB1b2/6p1/8/5r2/4N3/7K w - -,24,692,14174,396185,7904201,215377171 -8/rp4k1/1P2pnp1/5p1p/2R4P/2r5/3bK1b1/8 w - -,15,654,8966,385762,5206946,216282515 -r1b1k3/p2p1r2/n3N2p/1B1ppppP/1b6/PQ2P2R/2PB2P1/R3K1N1 b Qq -,23,1105,24601,1165958,26920082,1253029608 -8/1p1k3B/7n/3r2p1/1Kpp4/1R1b2PN/7P/5R2 b - -,31,918,26255,751021,20881561,599247739 -r2B1qr1/p2bbk1p/np2p1pn/2p2p2/4P2P/PP3P2/1R1PQ3/2B1KBNR w K -,30,928,29350,929745,31039725,1015022123 -r1br4/1ppp2k1/nb2pq2/pP4p1/P2Pp2p/1QB1nPPK/1RPN3P/5BNR b - -,45,1049,45233,1173998,48617793,1360117809 -1n4nr/p1kq3r/7Q/P1bp3p/Rp1PPP1P/1P4PR/3NN3/5K2 w - -,34,1004,33084,984675,32457395,988892512 -8/3P4/p4k2/P2Q4/N7/7B/4p3/4K3 w - -,40,158,5489,28418,973097,5272499 -b5r1/1k1B4/3n4/3p2p1/P2P3p/8/1Kn5/2Q5 b - -,28,735,18298,508790,12330888,342437466 -8/3Nb3/P1R3P1/4r2k/7P/1B1p4/K5N1/8 w - -,33,671,19866,403072,11944416,244803780 -2k5/8/8/1K3n2/8/7r/8/8 w - -,8,210,992,23975,125135,3004301 -8/3Nk2P/8/4P3/8/5K2/8/8 b - -,5,84,397,6725,30922,533369 -8/4r3/3NN2k/p4p2/P4Pp1/8/3K4/8 b - -,13,278,3711,69065,949866,16357695 -3b2k1/8/8/8/8/2K3p1/3p2P1/2B2b2 w - -,9,209,1712,40246,374287,8849397 -1n6/Bb3r1k/1P4R1/4p3/2pp1P1P/4Pp2/3n4/4R2K b - -,29,739,19677,483948,12891786,312830991 -4kb1r/4p1pp/1rp2p2/p1p1P2n/2PP1P1q/4n3/1BR1KN1P/1N3B1R w - -,29,1039,26802,952525,24608819,878730907 -8/q7/5k2/p2r3r/PP2p1P1/2KP4/2Rnp1B1/4N1N1 b - -,51,928,42944,823315,36611625,748113467 -2k5/4n3/5P2/2bb4/3p1bP1/3K2NP/8/1B6 b - -,37,504,17647,252394,8215987,126587107 -5q2/p2P4/P1n2Pk1/Bp1p2p1/3P3p/7P/6R1/4Q1KN b - -,31,1345,32516,1291688,29084514,1108229283 -r3k1n1/p2p2p1/1pr3N1/5pq1/2b2PPp/b1pQ4/P3PB1P/R3KB1R w KQq -,40,1754,66795,2868997,106764600,4506056720 -r1b1k2Q/bp1p1p2/n1pB1P1p/8/Pp6/1q2P3/2PP3P/RN2KBNR b KQ -,0,0,0,0,0,0 -1nb4k/3pp1r1/5pp1/qPp1b2p/5PPP/Bp1PP3/R3K1B1/1N4NR w - -,33,1231,38863,1385214,44466026,1555159559 -1r3k2/p2p2p1/1p5n/4NpP1/2rq1P1p/1bpQ3B/Pb1BP2P/R3K2R w - -,37,1433,49872,2035363,70997117,2962934564 -8/1k6/4p3/2K1P2p/2B1P2P/8/3N4/8 w - -,17,92,1655,6633,116053,532720 -r1b1kbnr/p3p1pp/np5q/2p2P2/NPPp1P2/P2P3P/4P2R/R1BQKBN1 b kq -,28,684,20913,559570,17898619,509813312 -bnn1k3/8/1B6/P1p5/2PpP2N/1p1P3K/8/6b1 w - -,13,247,3650,74577,1156305,24823020 -1rbq1bn1/pppp1rp1/4p3/P4Pk1/P1P3Pp/B6P/R2P1K1N/1NQ3R1 w - -,35,862,28341,698666,23205863,589091299 -1nbq1r1k/2pp3p/rpnP2p1/P5B1/3N1p1P/1Q3R2/P3PPP1/R3KBN1 w Q -,49,1202,57542,1539487,72064837,2064254825 -2b2R2/7k/8/2p2PPP/8/8/7p/6RK b - -,11,165,1615,30796,317946,6608795 -b1N1k3/8/2r5/5np1/pBp2P2/2b1p1PB/8/1K1R4 w - -,32,987,30183,933071,27640089,859383916 -2R5/p1q5/nkp1PQ2/1pb5/1P4p1/2P5/2KRB1P1/8 w - -,49,1166,51690,1223299,52561957,1273722657 -4k3/5r2/2N4P/1P1n2p1/8/K5p1/8/4r3 w - -,14,554,6287,226773,2559080,86572950 -3n1N2/1r2k3/B7/8/P2P4/1P3P1p/K1pQ3P/5R2 w - -,39,657,23523,452663,15789321,319586238 -4k1n1/2n5/8/1P1P4/5B1P/2pP3r/5KR1/1N4Q1 w - -,33,638,20944,414972,14046353,284749289 -1n1qkbnr/rbpp1p1p/pp6/4p1p1/8/5P1P/PPPPP1P1/RNBQKBNR w KQk -,18,613,12387,410945,9210148,303222533 -8/6r1/5P1k/8/qpP1R1P1/4n3/3K3b/1B6 w - -,19,738,13632,495611,9722820,344014927 -8/3b3k/7P/P3P3/2K3P1/4p3/3B4/8 b - -,14,193,2596,35738,480889,6712277 -4rbkr/3P4/6p1/p2np2p/2pQ1P1P/P3P3/5K1R/R1BN1BN1 b - -,32,1416,40217,1771396,47932537,2112923620 -BR4r1/3n3k/8/8/8/7K/2bp4/8 b - -,35,686,21180,420811,12862726,259426173 -1nr2k2/r7/1p5p/p2R4/b1P1pp1p/6N1/4PKB1/b5nR w - -,31,1330,36525,1516041,41443433,1678772687 -1K6/5k2/p1N5/p7/P7/8/1N6/4r3 w - -,15,287,4164,75912,1104108,19657629 -6k1/8/1R6/4b3/3p2b1/B5p1/6P1/1K6 b - -,21,489,9147,195748,3575826,75107901 -2r4r/1pp1k2p/3b1p1n/Q4n2/PP3P2/2p1B1Pq/4P2P/3RKbR1 b - -,41,1255,48455,1461321,56716440,1710895996 -5B1r/3n3k/1p2bpRP/1P1p4/8/1p1pN3/6B1/7K b - -,16,400,6947,174787,3354834,85494926 -r2k1bn1/pB5r/5p1p/1Pp1p2Q/P1P4P/2R2b2/3N4/2B1K1NR b - -,30,1164,30634,1256456,31764611,1341388874 -3bn1n1/8/Bp6/2kp1P1p/P3p3/1Pp4P/2R5/3K2NR b - -,20,509,9678,237142,4663815,113573182 -rnbqk1nr/p1pp1pp1/1p5p/4p3/1b1P2P1/2N5/PPPBPP1P/R2QKBNR b KQkq -,34,1010,34110,992552,33429271,985582255 -r7/pbkn2r1/2p3p1/1p3P1P/1P5R/1PB4P/P2KN3/r4B2 w - -,26,889,24009,805117,22309607,747726108 -5N2/b7/8/p4P2/P7/8/4r3/1K4k1 b - -,25,184,4373,37638,885282,8128558 -7k/8/1pb2n1P/1P1B1K2/8/8/2b3R1/8 w - -,7,149,3584,68481,1607993,30466664 -r4qnr/p1pbkppp/2n5/bp1p2P1/2BP3P/4P3/PPPQ1P1R/R1BNK3 b Q -,38,957,33861,902629,31629371,881908752 -3b4/1r4k1/6p1/p3p2p/P2rPP1P/8/3QK2R/1R1N2N1 w - -,36,1240,43477,1379001,49191825,1475459105 -r7/2b3rb/8/p1p1P3/P1Nk3P/1p2p3/3P1R2/3K4 w - -,23,804,16668,556785,11143090,363159031 -1nb3nr/2p1p3/4r1k1/ppP2pq1/1P1pP1Q1/N4KPP/P2b1P1R/1RB2BN1 w - -,28,950,26067,902176,26008811,913929727 -2n2k2/3bp3/N7/p6P/5P2/R3K2p/2r4Q/1r5n b - -,45,1063,44293,1147337,44829561,1221389245 -r1bn3r/2p3pp/1N1k2Pn/pP3p2/1b1ppq1P/BP3P1R/Q1PPPK2/4RBN1 w - -,27,977,23522,878297,22336924,849941694 -8/n2k4/p2p4/P2P2Q1/2pb4/P2K3N/2BBr2R/8 w - -,3,66,2668,49239,1992504,37861627 -8/2k5/8/2PP1R2/4p3/2K2Ppr/6p1/8 b - -,18,321,5845,101623,1937042,33200190 -8/7k/7p/1n6/3PK1p1/8/2PQ2p1/6R1 w - -,31,395,10640,144809,4093385,58551040 -8/4R3/1R6/2p5/2P1K3/q7/3k4/8 b - -,23,543,10483,236940,4608851,102985161 -6k1/1b6/7P/P3P3/1K3BP1/4p3/8/8 w - -,15,199,2946,39328,596102,8023450 -r1bq1bnr/pp3k2/2npp2p/5ppP/P1N5/1P6/2PPPPP1/1RBQKBNR w K -,27,807,22308,664309,18935001,571440507 -r1bq1knr/pp1p2bp/2n2pp1/2pNp3/6P1/4PP1P/PPPP4/R1BQKBNR b KQ -,27,830,23027,692812,19741247,592747438 -k4N1r/8/2P1K2n/1p1P2Pp/1p5P/rPq5/8/R6R b - -,34,743,24745,518428,17485308,366488461 -8/2r2P2/8/Q7/1p2BRk1/8/1b2K3/8 b - -,3,136,2950,121860,2513587,102346161 -8/k7/5n2/7b/1K5R/8/2p4P/8 b - -,23,347,7926,124998,2821907,45501795 -r2r4/p2k1RB1/P1b5/1PPPb1q1/B7/2n3P1/1P5P/1N2K3 b - -,3,102,3787,108139,4165491,117166417 -3k2r1/6N1/2n5/3pbP2/8/8/7n/4K3 w - -,8,220,1906,56320,497957,15031599 -5k2/6p1/8/4K2R/b3pP2/N2q2Pn/8/8 w - -,15,485,7009,223317,3378362,104781067 -1k3br1/8/1p5R/pP2pp2/B7/8/P1R4K/1n1N4 w - -,31,672,18803,441386,12101533,290947723 -2k5/bb5r/7p/B1P4P/4p3/Pn6/R2P3N/5K2 w - -,19,427,7782,187738,3635147,92299800 -6k1/7N/P5P1/3p4/3Q2B1/4p1pP/4K3/2R1N3 b - -,1,50,229,8819,59546,2012023 -Nb6/4B1nr/1p5k/3q1P1P/2P3pN/pp5P/P1KR4/R4B2 w - -,6,237,7565,254125,8102409,265435619 -q1r3n1/p7/P2p1R2/BpP2Ppk/3P2bp/7P/1RQ2N2/6K1 w - -,40,959,36808,949008,37274779,1012196130 -2bkq3/4p3/1rpp1nQb/2nP2pp/pBP3P1/PP2PN1P/3NKP1R/2R2B2 b - -,40,1639,59995,2356499,83330544,3217360080 -rnb1k3/p7/P1ppp3/1pq1P3/1P3np1/2PP2b1/3RN1PQ/2K2B2 w q -,25,737,17459,499594,12165736,342888471 -R7/5qp1/7n/2K1k3/4b3/8/8/8 b - -,43,622,23360,314171,11115766,148671224 -1N6/8/8/3k4/B5r1/1P3P1p/7P/2K5 b - -,19,243,3830,55244,840243,12698264 -r5k1/2q5/1pn1p3/pp1pBp2/P4Pp1/3QN3/5Kb1/6N1 b - -,38,1463,53287,1937559,67492652,2343524554 -rn2kbnr/p1p1p2p/3qbp2/1p4p1/2B1P3/NQ6/PP1P1PPP/R1BK2NR b kq -,43,1430,53648,1809963,64702348,2205979759 -rn1q4/p2p2p1/1pp1p2k/5p1n/P4R2/N3Pb1B/3K1P2/2BQ2N1 w - -,31,1001,32843,1030768,34822625,1075560724 -r1bq1bn1/pppp1p1r/2nkp1p1/7p/1PP5/P2P1P2/4P1PP/RN1QKBNR b KQ -,32,682,20768,485263,14664766,364238407 -4k2b/8/1p5N/PP6/4K3/6b1/3R4/5B2 w - -,30,565,15490,293627,7833704,147629713 -5k2/5bp1/8/pp2Kp2/P3PP1p/3R2qn/3N3P/6q1 w - -,21,893,16351,682634,12029275,493511041 -bnR4r/3k3p/2p5/p1Pp4/P7/3p2q1/3P3n/1NB4K w - -,12,329,4306,123777,1780398,52301343 -6rr/1pp1k2p/5p1n/Q4n2/PP3bP1/2p1B2q/4P2P/3RKbR1 w - -,36,1359,44495,1715654,55181892,2157009323 -BNr5/8/6k1/6P1/2B5/8/K4R2/3bN3 b - -,21,800,15792,561035,11089037,381294908 -7N/2k5/8/2P5/8/8/B7/1K6 b - -,6,77,402,6532,31453,534781 -6Bk/1rB5/8/P7/1p2K2p/4b2N/R7/8 w - -,35,665,22280,423386,13576666,266970239 -7k/1B5n/3R3P/5b2/5K2/8/2b5/8 b - -,18,462,8685,207996,4011992,94259513 -2bqk1nr/p5bp/n2p1P2/p1pPp3/P5p1/RrP5/1P1NPP1P/2B1KBNR w Kk -,22,711,17071,564894,14326315,482320210 -3rk2r/p4p1Q/3p1npb/1pp3P1/P2pP3/4qR1b/1PKN3P/2B4R w k -,31,1293,35865,1450461,40881971,1612753668 -8/4r3/8/p4N2/P2b1P2/5k2/8/1K6 w - -,11,297,3111,81362,831458,20576041 -1n6/BP3k2/b7/2n1PP2/2p4P/5pr1/5K2/6R1 w - -,19,432,7831,178853,3503474,81445520 -6b1/1r1Bk3/1p5N/P3PP2/4b1PK/4n3/8/4BR2 b - -,33,826,23626,610325,17333023,459599983 -rnb1k2r/3pqpb1/pP2p3/2p2NpQ/1P3P1p/B2PP3/2PK2PP/RN3B1R w kq -,39,1148,42682,1245972,46330776,1372393339 -b2r2kr/3n4/7p/pR2b3/2p4p/3NPp2/5R2/6KB b - -,35,1082,36200,1088044,36606991,1080300102 -8/p2k4/P7/BK6/8/7p/8/8 b - -,6,69,465,6064,50749,671258 -8/8/8/6k1/8/1B1p2K1/8/8 b - -,6,95,631,9412,74180,1036141 -8/1k6/5pP1/p1p5/P1P3K1/1P6/N3Rr2/R7 w - -,27,442,10575,164846,3995507,62753952 -1r6/3r1b2/5k1p/PBpp2n1/3PpK2/1P6/4R2R/B7 b - -,33,935,28575,839657,25266360,749119898 -6k1/8/5PP1/7P/2p3K1/8/8/R6b w - -,23,207,4187,43843,844924,8971623 -6nr/k1r5/8/np1P2Pp/1p1P3P/RP2KN2/8/1qN3R1 b - -,35,719,24721,523073,18349358,395499975 -2k1N3/1N6/r7/1P1P2pP/8/5rp1/n7/K7 b - -,32,393,9985,124304,3169457,40920133 -1rb1k1r1/p1p1p2p/1p2P2b/Q2p1np1/NP1B1pP1/P1nP1PN1/4q2P/3R1K1R w - -,2,80,2546,95781,2994218,109425287 -b3n1r1/k2B4/8/3p2pp/P2P4/b7/K6Q/1R2n3 w - -,40,881,33623,804208,29542369,745244186 -2r5/p1k5/2b4n/2Pqp3/Q1PPNp1p/4RPpB/1K2RP2/8 b - -,36,1454,49837,1936628,66737875,2541809001 -6nr/1p3k1p/5p1b/1qp1p1p1/pPN3P1/B1P1pP1P/P2PKQBR/4R1N1 b - -,23,572,13931,372350,9530424,267695522 -r7/3kN3/N7/1pK1P3/2P2R1P/5p2/8/8 w - -,25,354,8560,113294,2712587,37019497 -5k2/2Q5/3R3P/1pp2r1r/1p6/P1b3KB/2N3n1/8 w - -,41,1024,34895,887331,30903906,802264452 -1Nb1kb2/2B5/P3p1p1/3Pr2p/2P2P1P/8/4R1r1/n1K4R w - -,33,959,27193,803147,22552093,677335964 -r4qr1/p1B2k1p/1p2pnp1/2p5/P1b1Pp1P/1P3P2/1R1P2B1/2BK1R2 w - -,24,872,20723,741287,18320071,653233225 -2b1r2r/4p3/5P1k/2p2P2/5R1P/6Pp/4q2K/4R3 w - -,5,169,3488,116716,2570969,87774938 -8/5k2/2Rb4/8/3p4/6pb/1B4P1/2K5 b - -,24,435,8365,159316,3021967,59071819 -b3k3/n7/5nN1/P1p5/2PpP3/3P3K/1p6/6b1 w - -,11,275,2831,73310,775213,20610958 -1rbk1bnr/pp1p1ppp/n1pq4/4pP1Q/P1B1P3/2P4P/1P1P2P1/RNB2KNR b - -,31,1107,33091,1136579,34495551,1167218839 -7k/8/n5P1/r7/1pbp1p1p/1P4nP/2K5/8 b - -,33,213,5745,31234,787837,4240366 -2b2q2/p1rpn1p1/P1p5/1pP2P1k/PB1P3p/4R2P/1R2K3/1N2Q3 b - -,21,861,19408,750768,17511676,661803327 -5k2/3b4/7P/P3P3/2K3P1/4B3/8/8 w - -,21,240,4205,48806,837155,9908402 -8/3k4/5P1p/rpn3p1/7P/5K2/4rR2/8 b - -,37,399,13419,181638,5844975,87657554 -8/P6B/7k/8/1p3K2/r5Np/8/8 w - -,21,324,6699,102718,2212126,35495166 -1rbqkbnr/1ppp2pp/p7/1B2pp2/3P3P/1PP1P1Q1/P4PP1/RNB1K1NR b KQk -,27,1095,28884,1141722,31283595,1212274597 -b4r2/8/4q3/p4B1k/P1P2P1p/8/2K5/3R4 b - -,39,1000,34282,801276,26886772,598026976 -8/1k2Nr2/3Q4/Pp6/4r3/1p5K/1b6/8 w - -,33,917,24140,694880,17691428,515775797 -6B1/R7/k7/1p6/2P5/5n2/8/2K1N3 b - -,2,42,533,12036,135109,3107727 -1n5k/1b3r2/1B4p1/1P1ppp2/2p2PpP/1p2P3/3N3N/3R1R1K b - -,24,608,14858,415729,10253647,303718206 -4k3/8/7B/2K1P1P1/pp3R2/P4B1p/1P6/8 b - -,6,208,1353,45045,333053,10629266 -1rbq1bn1/ppppp1p1/6r1/PB3k2/P6p/B1P2N1P/3P1PP1/RN1QK1R1 w Q -,33,750,24631,553868,18803545,435427953 -7r/5b2/2B2k1p/r1pp2n1/1B1P1K2/1P2p3/4R3/7R b - -,34,1223,40019,1378356,44462155,1484863617 -2r1k3/8/p2p1n2/P1p1p3/1R2PP1p/1bK3QN/B5P1/3N3R w - -,38,1067,38652,1000165,37468721,922542946 -rnbqkbr1/ppp2ppp/3p4/4p3/P2PP3/3Q4/1PPB1PPP/RN2KnNR b KQq -,35,1480,51711,2081723,73436472,2854666165 -rnbqkbnr/ppp1pppp/8/3p4/2P2P2/3P4/PP2P1PP/RNBQKBNR w KQkq -,27,753,21149,615738,17906155,544287400 -rnN5/2k3rb/1p6/1Q4p1/1b1PPPPp/PP2BN2/b6K/3B3R b - -,33,1469,42933,1799741,53842184,2182489500 -rn2b1nr/4b2k/1R1pP3/7p/pP2PP1P/p5p1/2KB1P1R/1NN5 w - -,26,656,18082,477933,13580203,375457080 -2r5/8/4K1pP/5n2/7k/2p5/5p2/8 w - -,6,173,929,25718,162919,4441141 -6k1/4b3/8/8/8/B1K3p1/4b1P1/3n4 w - -,4,104,958,23043,238225,5582812 -8/5k2/8/2n4p/7P/4R3/3K4/8 w - -,20,258,4495,53017,919586,10044737 -7Q/k7/8/b7/8/3K1Q2/6P1/5B2 w - -,48,362,16806,140199,6385759,56318885 -b5r1/1k1r2N1/p1p2nP1/Pp5P/1P2R3/1P3B1P/8/1rB1K3 b - -,33,745,23044,552230,16676642,412809463 -6b1/r1k5/2NR4/8/p2p1K2/P2P4/3r4/4N3 b - -,24,577,14070,328211,8085565,185846940 -8/2k5/7R/2PP4/K3p2r/3q1Ppp/8/6R1 w - -,26,679,12157,333002,6347514,175742988 -5k2/2r5/p2N1b2/p1p5/P3n3/N3KR2/8/7N b - -,19,466,10365,240078,5682167,134203393 -rn1q4/p2p2p1/1pp1p1k1/3b1p1n/Pb1R4/4PR1B/3P1P2/1NBQK1N1 w - -,27,937,26865,915565,27896039,937370830 -rn2qb1r/N1pkp1pp/Qp6/3b1P2/2pP1P2/3BP2P/PP1N4/R1B1K2R b Q -,31,1178,33897,1276238,37223691,1401357060 -r1Q5/4n1k1/1p2p3/p2N1p2/Pp3Pp1/7b/4NK2/8 b - -,20,600,11700,322516,6515850,177018202 -8/8/5P2/p4N2/Pb1K4/5r2/8/4k3 w - -,12,271,2907,63492,686075,15094491 -8/1p2k2B/7n/3r2p1/1Kpp4/2Rb2PN/7P/6R1 w - -,25,745,19780,552284,15341736,414239667 -1R6/p6k/P1P5/2P3r1/7K/8/1P2Br2/8 w - -,25,570,11318,258561,5022218,115434437 -2N3k1/5r2/N2p1q2/Bp3n2/P1P3Pp/1P1P1P2/4Q2P/2K1RB1R w - -,44,1481,58268,1938365,78057244,2561319887 -rnbqkbnr/1ppppppp/8/p7/4P1P1/8/PPPP1P1P/RNBQKBNR b KQkq -,21,609,14134,407898,10307797,304330115 -rn3b1r/p1p1p2p/B1k2p1n/1p4p1/8/N7/PP1P1PPP/R1B1K1NR w - -,24,402,9998,191096,4928004,102895527 -1r1k1bnr/pp1bqpp1/B6p/2p1p2Q/P3p1PP/2PP4/1P1K4/RNB3NR b - -,31,844,26517,806522,25776504,836174494 -1n1r4/p4k2/2n1R3/8/pP1p1K1b/5p2/1N3P2/B5n1 b - -,29,511,14141,249551,7025725,128082309 -3qkb1r/2p1n2b/p2p3p/Pr2pp2/3P1P2/P5p1/6BR/R1B1KQN1 b k -,33,1100,35182,1264449,41361764,1523326391 -4N3/8/5P2/p3K3/Pb6/2r5/6k1/8 b - -,27,245,6409,62451,1580559,16633324 -8/3k4/p2b1R1p/P7/8/2Q5/4b3/3R2K1 w - -,45,558,23231,351441,14129640,222592029 -r1bqkb1r/pppppp1p/2n5/6B1/4P3/2PP1K2/PP3PPP/RN1Q1BNn b kq -,23,740,18853,599565,16521361,518815967 -3k3r/1r5p/p4b2/npp1p1PP/2Pp4/PN3K1Q/RP2B3/6N1 b - -,25,740,18241,547396,13944838,430429793 -4k2r/6Rp/5n2/p2p1P2/2P1N3/b3K2N/2Rp3P/1r6 b - -,40,1361,45872,1443831,47494524,1431424624 -8/6kN/8/6q1/Pp1rp3/2RP1N2/3Kp3/1r6 w - -,4,155,2848,103116,1935527,69634302 -6k1/8/8/8/1K3b2/8/8/8 b - -,16,120,1784,11117,162376,1044597 -1nbq4/3pppkr/6p1/1ppBb2p/P4PPP/Bp1PP3/8/RN1K2NR b - -,36,1204,41906,1381919,47336501,1564309444 -r1b2bk1/1p2p1Bp/3p3n/p5p1/2P1pP2/6PN/3K3P/R4B1R w - -,34,766,24404,583202,18398467,459032557 -r5rk/1p6/n7/3pp1p1/PB4K1/1p4P1/2q3NP/RN4b1 b - -,51,1072,51344,1076950,49277574,1061804695 -3B4/3k4/7R/N7/p1bp1p2/P2P4/4rKN1/1r6 w - -,2,66,1849,52422,1381088,37785568 -r1n5/5Nk1/8/2K5/4bBp1/6PR/8/8 w - -,26,686,16870,438621,10648311,276903571 -4k3/7B/1p5n/4r1p1/1K2bR2/2pp2P1/7P/1R4N1 b - -,29,889,25038,754002,21330806,638163019 -rn6/p2p1q1k/1pp1p1p1/1R3p2/P4P2/N2Q4/3K1Pb1/2B3N1 w - -,42,1016,39961,1027527,38183416,1025176824 -2k5/8/4P3/Q6B/8/8/2K2bP1/8 w - -,38,376,13256,134780,4551624,46853944 -R7/8/1B3N2/5k2/5P2/3r3p/4KRp1/8 b - -,21,625,13040,372628,7831809,223788051 -1rbq2n1/p2p2p1/P1pbp3/1p3rk1/PBP3Pp/7P/R2PR2N/1NQ1K3 b - -,43,1311,47882,1500687,52648694,1696339200 -rQb2kn1/1p1pq2r/p7/1N3pN1/PbP1p2p/3PPP2/1P1B2PP/1R1K1B1R w - -,42,1381,56226,1874352,74803261,2521531210 -r2k1b1r/1p2pP1p/p2pQ1p1/2qp2P1/nP3PR1/P1PK3B/2N4P/RNB5 w - -,33,895,25656,695622,21119626,583051267 -3n4/5b1k/4p3/4P2p/Qp2P2P/8/N3K1B1/8 w - -,28,299,8356,89225,2488511,28906978 -3n2k1/5b2/8/pP3B2/P4pP1/1R2PR2/5K2/2b4r b - -,29,623,17486,389679,11066959,258281783 -6b1/2n2k2/2B2B1p/8/6K1/1r1p3R/4p3/R7 b - -,26,1157,30666,1230923,33663026,1259623942 -1nb2knr/7p/p2N4/p1pP4/P1rb2p1/3RPP2/5N1P/q1B1KBR1 b - -,33,1029,36162,1119115,40799066,1257572303 -1N6/8/4Q3/2k5/4PK2/2p5/4Q3/1R6 b - -,2,122,461,21417,135547,6005714 -3k2nN/8/3p2B1/3P2b1/4pq1R/5P1p/1r6/2nK4 b - -,44,626,24845,350968,13686399,204479705 -rnbqkb1r/1p1p1pp1/p1p1p2n/6Pp/8/3PB2P/PPPQPP2/RN2KBNR w KQkq -,28,802,23856,707778,21924775,666031148 -1N3RB1/8/P5k1/2r5/7P/3p4/K7/2b1N3 w - -,27,566,14965,308580,8509434,176776277 -8/k7/8/3B2b1/1K6/5rp1/8/8 b - -,25,389,9268,125685,3034335,38972773 -4B2k/8/4P1R1/1p2BP1K/8/8/8/2n5 b - -,1,31,159,4690,30632,827356 -8/8/6P1/8/1kb4P/8/1K6/8 w - -,6,100,649,10016,77697,1114696 -rnbqkb1r/p2ppp1p/5n2/1pp3p1/5B2/P2P4/1PPNPPPP/RN1QKB1R b KQkq -,27,738,21187,600908,18123208,530640296 -rnb2br1/pp5p/4p1k1/4np2/P1PQ2Pp/2P1N2N/4PP1B/1R2KB1R w K -,44,1310,54304,1557019,65011119,1853626353 -8/5b2/4k3/1P6/8/3B2BR/5K2/n7 b - -,10,301,3794,118252,1577390,50125467 -6n1/2p1k2r/P2r3p/P2p1ppq/1n1PPP1P/1P5b/B2K4/R1BNR3 w - -,21,805,17403,666709,15069815,571816879 -1n1rkbr1/1p1bN3/3pp2p/q1p3p1/1n2p2P/PQPP1P2/1P2N1P1/R1BB1K1R w - -,42,1604,67090,2472800,102681196,3717522806 -r1bqkbr1/p2p2p1/np2pn2/7p/P1pP4/8/RPP1P1PP/1NBQKBNR w Kq -,27,757,20999,632364,18346834,581030619 -8/2b3k1/4Brp1/p3p2p/P3PP1P/1Qr5/3p1K1R/1R1N2N1 b - -,26,896,23236,871492,22613752,876286839 -3kn3/1r3R2/Pp6/2p2B1P/1NP1p1p1/1R6/8/4K3 b - -,14,489,6841,235031,3489395,116764225 -5k2/8/3P4/2P5/7R/1K4pr/4p3/8 w - -,22,268,4995,83131,1457624,27857602 -3q4/8/2P5/8/7k/K4Q1p/8/8 b - -,22,433,7332,149601,2771371,56455984 -rn1k2r1/1b1pqpb1/1P1N2Q1/p1p1p1p1/1PPPPP2/B6p/3K2PP/RN3B1R w - -,42,1293,52613,1593982,63664761,1943229099 -r1n5/8/6kB/2K3N1/4b1p1/6PR/8/8 b - -,25,366,9569,172136,4486438,89619180 -rn4r1/p2kp1bp/B1p4n/4BpN1/3P4/8/PPp2PPP/R3K2R w - -,39,843,29389,712385,24608427,641474146 -1n3R2/3pBbkp/B5p1/Pp5P/P1qpPp2/5R2/5PP1/R3K1N1 b - -,31,1083,30635,1112399,31355924,1163287412 -6k1/7b/1p6/8/8/8/n2K3n/8 w - -,4,68,279,5603,24578,517763 -1n4kr/2B4p/3b2b1/ppp5/Pn1pP3/3P4/2PN1K2/3R4 w - -,27,741,19008,526586,13537060,380644211 -3r4/7r/q4k2/p3p3/PP1Q3p/2nPppP1/1RKN2B1/1R4N1 w - -,41,1838,73310,3155675,122724141,5122498430 -1k1q4/3n1n1p/2b5/P2p4/8/3pN2K/3P4/6B1 w - -,15,476,7437,235185,3696844,118264308 -1rbq2n1/pppp1rp1/P2bp3/5Pk1/P1P3Pp/B6P/R2P1KRN/1NQ5 b - -,32,948,26466,809829,22717021,717152721 -7k/1N3R2/8/1p1pP1BP/P7/1b1pP3/3K2P1/8 b - -,9,292,2361,70913,629879,18003706 -r1b1kb1r/pp1pp2p/5Ppn/q1np4/5PP1/P1P4B/1PNQ3P/RNB2K1R w k -,29,917,27835,897714,28685749,944609500 -8/1r6/8/k7/N2P1K2/P7/3R4/6r1 b - -,31,547,15378,291120,7627726,147145864 -8/8/8/8/2B2k2/1p1p4/8/7K w - -,11,99,1149,10014,117631,1079896 -1n1b4/6K1/1k2P3/2p1n3/2Pp4/8/8/5b2 b - -,28,176,4689,27537,696131,5302556 -4k1b1/1NB3r1/3r4/6b1/p1Pp1p2/P2P3N/4K3/7R b - -,31,811,23551,609930,17537276,452088001 -rb6/r6b/8/p1p1P3/P1Nk3P/1p2p3/3P3R/3K4 b - -,24,395,10195,171137,4683236,80542513 -3R4/7k/7P/3B1bn1/8/5bK1/8/8 w - -,24,514,12647,261448,6212793,129006278 -br4r1/3B2B1/p1p4p/1N5k/1P2P3/3p4/P7/2RK2b1 w - -,34,933,30271,842845,26395297,748424426 -1Br5/4k3/1b6/1p1pp3/8/R3NKPN/1p6/7r w - -,31,1199,32682,1227470,32198356,1180073304 -8/2k3b1/8/7R/8/3K2N1/2b5/N3b3 w - -,5,142,3329,85332,1930868,47995002 -r2n1r2/1bNk2pp/6P1/pP3p2/3pPq1P/1P1PBR2/2P3p1/Q3K1N1 b - -,39,1418,53579,1901192,71359399,2503173498 -4k3/4rn2/p2P2B1/p1p5/P7/N6P/1b3R2/1n2K2N w - -,5,117,2961,67245,1750595,41123379 -5R2/6n1/4k3/7b/5p1p/r2p3P/3n4/2K5 w - -,13,348,4244,115097,1432709,39183407 -B7/3N2B1/3k4/p7/1p1K2P1/P4R1p/1P2P3/8 w - -,38,269,10274,74138,2794088,21786742 -4r3/2NkN3/8/1pK1P3/2P2R1P/5p2/8/8 b - -,14,369,4877,122255,1673436,41139748 -4k1r1/rb2b2p/p1n2pp1/2PppP1P/Q1pBP1R1/N7/P2PK3/3R1nN1 b - -,26,995,27230,1061448,30669184,1210984892 -r3k1n1/4b3/BB3npq/5p1r/pP2PP1P/2P5/R3R3/1N2K3 w - -,37,1044,37452,1140855,39636217,1275534719 -rn2kbnr/p1q2pp1/8/1pppp2P/5Pb1/PB2P3/1PPPQ2P/RNB1K1NR w KQkq -,31,1260,38967,1574750,49489054,1984205946 -3k4/7r/p2p1P1p/P6P/1bb5/3p2R1/3R1KP1/8 w - -,21,503,10373,251924,5323007,130765630 -1n1kn3/N1b5/ppb4p/3ppr2/3pPp2/PPP2K1P/4B2R/3RB1N1 w - -,31,669,20224,460542,13940975,332636690 -8/1k6/3b4/1Q6/8/3K4/6PQ/5B2 b - -,4,172,1569,66088,574757,24329604 -5b2/r2q1k1b/1pp1pnpr/p2P3p/5PPP/1QNP2NR/PP3KB1/R1B5 b - -,36,1462,51390,2103583,73789338,3035631509 -8/k7/2K5/8/8/b5p1/8/3B4 b - -,11,126,1534,19085,247779,3172289 -8/p5k1/P7/1p1p4/3P3p/7P/3qN2K/B7 w - -,5,122,1079,24957,233785,5206069 -2k3r1/6n1/8/1K6/2n5/8/8/8 w - -,6,114,542,11659,64486,1511637 -2bQ4/5n2/2P2rk1/3p1p2/Pp3PPp/1P5P/2K5/5R1n b - -,20,607,11547,338316,6674959,191450770 -k7/7r/8/8/2pK4/2PN4/8/8 w - -,14,242,2812,46150,520040,8431979 -1B1N3k/4r3/5b1P/2n1P3/3K2p1/6P1/4b3/4R3 b - -,31,587,16700,340453,9544670,201645201 -5k2/3P4/8/2P4r/1R6/1K4p1/4p3/8 b - -,21,475,8926,196892,4009634,85434344 -r1bqkbnr/ppp1p1pp/2np1p2/8/P7/2P5/RP1PPPPP/1NBQKBNR w Kkq -,21,564,13459,374543,9810767,279829399 -5n1k/8/4B1p1/4p2p/5b1P/5r2/5K2/8 w - -,5,106,1317,31046,352403,8584620 -6r1/p1p2kp1/n3b2p/Pr2PN2/2P1P1P1/1P1KbP2/4N1q1/1R6 b - -,51,1319,61300,1459426,66532275,1525652210 -1rb1k1r1/p1p1p1bp/1p2P3/Qn1p2p1/NP1B1NP1/P2P1Pn1/7P/3R2KR w - -,35,1138,37780,1213056,41006367,1303038181 -6R1/p7/n3k3/3N4/3p1K2/5p2/3B1b2/6n1 b - -,15,341,5334,121523,2036934,47252936 -8/8/P7/2p5/PkP1Rp2/5N2/7K/8 b - -,5,108,584,12801,74362,1664448 -2B1k3/7N/1Q6/PN1p2P1/1R3b1p/4p2P/4K1R1/2r5 b - -,24,1032,18548,799906,13985559,606645570 -8/7p/R6P/3K2kP/4r2n/2p2p2/8/8 b - -,22,352,7510,112131,2387686,36788255 -b6r/n2p4/5npb/p1p4k/P1p1Pr2/5P2/2K3BP/1R6 b - -,34,821,28346,581684,20260521,392291944 -r1bn3r/p1pk1ppp/7n/1P1N4/1b1ppqPP/BP3P1R/Q1PPPK2/4RBN1 w - -,30,1248,34827,1433971,41976876,1710295694 -bbn4r/q1N4k/7N/p2P4/2PBp2p/3BPP2/P2K4/2R2Rr1 b - -,31,1290,43605,1715198,61898393,2352513075 -rnbqkbnr/1ppp1pp1/4p2p/p7/4P3/5P2/PPPP1KPP/RNBQ1BNR w kq -,29,866,24021,726774,20567096,634517419 -6k1/rp6/1b3B1r/P1npp1K1/8/6P1/1p1N3P/R3N3 w - -,29,966,24207,819564,20541761,703683026 -8/1Q6/5k2/p2p1pp1/R4P2/4B1P1/6P1/1b2bK2 b - -,14,508,6380,221381,3000519,100836615 -rb6/5b2/1pr5/p1k1P3/PpP1p3/5R1P/3P2R1/1N1K4 b - -,26,805,20801,594908,15813689,437103379 -8/3q4/2P2P2/8/p4k1p/8/1K6/8 b - -,31,251,7016,45576,1195273,9188872 -3k3r/1R6/2P4n/3p1PN1/8/3K1Nr1/7P/n3b3 w - -,27,556,13331,315489,7547882,194445968 -4k3/1B5N/p2pp2b/PRr5/6Pp/N6P/2P2r2/3Q1K1R w - -,3,102,3626,106838,3892138,107540995 -6k1/8/8/6b1/8/6p1/2Kpb1P1/2B5 b - -,29,185,4888,40871,1052414,9924699 -1k6/1b3n2/1p6/1R3rp1/6P1/K1pp3N/7P/8 b - -,29,522,14343,252604,6869755,123025768 -rn1k1bb1/NQ1q3r/1pp1p3/5Ppp/3PPP2/P4N1P/1Pp1K3/1RBB1R2 w - -,40,1445,55185,1952238,74010088,2614719519 -1R6/6p1/8/6k1/4K1n1/8/8/3bq3 w - -,3,108,1474,50885,657399,22461585 -5bk1/2n2R1r/1p4Bp/Pp1p2pP/3P2p1/R3K3/2P3Q1/5N2 w - -,44,722,30492,514802,20842971,365291634 -3k3r/5R2/7n/2Pp1PN1/p7/3K1Nr1/7P/4b3 w - -,22,453,10127,231860,5416326,133248818 -3b4/2r5/7k/8/4b3/2p4B/1n2K3/3r3n w - -,8,390,3042,142441,1235215,56388312 -rnbqkb1r/pppppp2/8/6pp/P2P2n1/4PN2/1PPQ1PPP/RNB1KB1R b KQkq -,26,839,22769,772961,21880607,770083053 -rnbqkbnr/1p2pp1p/3p4/6p1/P1p2PP1/1p1P4/2P1P2P/RNBQKBNR w Kkq -,27,907,24852,862095,24661026,879904215 -1B4nb/4k3/2rR2p1/N4p1r/pP5P/2P2Kn1/8/2R5 w - -,32,847,26958,756848,24207528,701822692 -8/5k2/4R3/K1PP4/4p3/6p1/8/4r3 w - -,18,251,4063,61735,1000153,15878747 -8/7k/np6/8/8/5p2/K7/6n1 w - -,5,65,340,4941,26902,422358 -8/p7/n3k3/3N4/3p1KR1/5p2/3B1b2/6n1 w - -,23,328,6181,99593,2062038,35147421 -r2b4/2r2k2/8/1p6/3p2P1/R1N2KB1/1p6/6N1 w - -,32,1089,32899,1122931,32840477,1126806542 -1r3rk1/npq1ppb1/1p3np1/2p2b1p/P1PB1N1P/3P1PP1/1P1NB3/2RKR3 w - -,30,1165,35147,1346038,40561965,1552867317 -6k1/B7/3b4/8/5K2/8/8/1b6 w - -,4,92,1002,21777,260009,5520152 -8/8/r7/k7/2K1b1p1/8/7p/8 w - -,4,118,534,15305,72019,2126483 -rnbqkbnr/ppppppp1/7p/8/8/1P1P4/P1P1PPPP/RNBQKBNR b KQkq -,19,531,11436,316231,7645220,214492317 -6kb/8/5R2/8/3p4/B5p1/K1b3P1/8 b - -,14,272,3630,70473,1010901,19981895 -rnbq1b1r/pppppk1p/5p1n/4N1p1/1P4P1/P1N1P2P/2PP1P2/R1BQKB1R b KQ -,5,173,3482,118004,2569658,87217542 -rnbqkbnr/pp1ppppp/2p5/8/8/4P3/PPPPNPPP/RNBQKB1R b KQkq -,21,481,11599,290439,7769383,211796571 -r1bqkbnr/pppp2pp/4p3/5p2/3P4/2P1P1Q1/PP3PPP/RNB1KBNR b KQk -,29,1032,29229,1048519,30050239,1083472965 -8/8/4k3/8/1p1p4/8/6B1/1b5K w - -,10,138,1576,22649,269252,3961881 -rnb2bnr/p1ppk3/4p1pp/1p3p2/P1PPP3/RP4Q1/3K1PPP/1NB2BNR w - -,41,948,38010,912456,35929032,891157865 -1n6/1b3rk1/6p1/1PBppp2/2p2PpP/4PN2/1p5N/4RR1K b - -,28,747,20639,578358,16171024,472941805 -8/5n2/8/1K3k2/8/8/8/8 b - -,14,108,1388,8589,108901,705795 -3N4/2nk4/2r5/4Q2p/7P/3RB3/3K4/8 b - -,3,132,1828,73773,1093808,44024345 -1r6/R6p/2K4P/6kP/2p4n/5p2/8/8 w - -,19,427,6881,149661,2436084,52319208 -3k1r2/1pN2p1p/3ppn1b/q5pP/P1p3B1/3P4/2QKP1n1/R1B3NR w - -,2,77,2377,84514,2830298,98759281 -8/2k5/5pP1/P1p1r3/PNP4K/8/8/R7 b - -,19,342,6035,112795,1930566,37162428 -rnb1qb1r/2pppk2/pp6/5ppp/P1PP2n1/4P3/NP3PPP/RQB1KBNR b KQ -,30,787,23727,672715,20900751,627542090 -1n2kr2/N1bb2np/pp6/3ppp2/2Bp1pPq/PPP1PK1P/3B4/3R2NR w - -,28,1068,26341,966238,24717473,890769934 -4k2b/1B5N/p1rp4/P3p1P1/1RQ4p/N1P4P/4K2R/8 b - -,12,525,6922,310561,4464275,199108956 -2k5/K2R4/2N5/8/7P/5p2/1b3r2/8 w - -,24,319,6786,112707,2264165,41081303 -4k3/7p/5r1P/pppR3r/1Pn1Q3/P1b3K1/2N5/5B2 b - -,6,222,7534,274078,8916463,315823208 -2bQ4/5n2/2P2rk1/3p1p2/Pp3PPp/1P5P/2K2n2/R7 w - -,30,642,17870,381711,10421088,226227853 -1r2nbr1/3kp1pp/7n/p1p2pQ1/1p2N2P/2Pp1R1K/PB6/RN3B2 w - -,42,1026,41541,1038258,41514201,1066944341 -6r1/1k1n1p2/1p5b/pPN1p3/B7/6RK/P7/2R5 b - -,7,248,6851,220920,5662564,173752155 -3n4/k2B2r1/r7/p3p3/6p1/4K1B1/1b6/3N4 w - -,22,642,13323,394970,8252890,248844650 -3k4/8/2r5/3BR3/p4P1p/3K2b1/8/6r1 w - -,27,788,19349,555878,12965245,375277369 -4N3/5k1b/4R3/1B4P1/1P5R/p5B1/4pK2/8 b - -,15,608,8415,335573,4939294,195067369 -5R2/2B4n/2r1kbp1/5p1r/1P5P/p1P5/2N5/2R3K1 b - -,27,863,21889,688129,18157347,566552394 -4k1nr/2p1qp2/p3r1pp/1P1p2P1/Pn1P1P1P/1P2P3/7R/RBBNKb2 b - -,37,1125,42363,1233688,46735290,1334968007 -2rk2nN/6b1/3p4/1q1PpB2/R4p1p/3n1P2/4K1R1/8 b - -,43,1204,47235,1296356,49059105,1326860733 -8/7N/3r4/5k2/8/1P3P1p/4K2P/8 w - -,9,163,1575,25384,260018,4090141 -8/2p5/1p6/1p3p2/5P1p/2k2n1K/7N/r7 w - -,4,118,805,20837,151496,3556369 -6n1/r5r1/5p1p/B1k4P/P5P1/3P1P2/2N2b1K/6RB w - -,27,686,16650,413729,10083015,256239243 -rn5r/3bb2k/1R1pP2n/7p/pP2PP1P/p1NN2P1/2KB3R/8 w - -,35,1011,34847,1046443,35560632,1098914072 -5k2/6p1/3Kb3/pR6/P3pP1p/6qn/3N3P/7q w - -,26,1043,22498,873929,17366426,671178224 -6k1/8/1P6/p4BP1/P4r2/3R2b1/1K6/8 b - -,19,521,10456,271425,5593804,139134148 -8/4P3/2kb4/8/5Q2/3K4/6P1/5B2 b - -,15,524,5952,192453,2119447,68807742 -2r5/1k6/1B6/5Ppp/Pq5P/8/1R4KR/8 b - -,41,1019,31943,800502,24700309,621164142 -8/7k/5b2/1p6/3p2P1/1R4B1/r2N1K2/3r4 w - -,20,628,13176,401420,8993982,271923308 -2r5/n3b3/5kp1/pP1P1p1r/P1b2P1p/B2pP1Q1/6Pn/3RK1R1 b - -,35,825,24426,597538,18484256,470134109 -2k1r3/3Rn3/2Pb4/3p1P2/3N4/8/8/3K1n2 w - -,18,357,6599,145013,2774378,65233006 -2bq1bn1/1ppp1p1r/r1nkp1p1/p6p/1PP5/P2P1P2/R3P1PP/1N1QKBNR w K -,26,849,22096,704735,18842595,594007789 -1n1r2k1/3b2br/6Rp/p7/2p4p/4Pp2/2N2K2/5R1B b - -,22,647,16976,476704,13670679,382032881 -1r1q1bn1/4pk1r/5p1p/pp1P3P/Pp2Q3/2N2PP1/2RP2B1/1NB2RK1 b - -,22,821,18628,700090,17469782,662678420 -rn1qk1r1/4n2p/1p2p1p1/8/P5P1/4P2P/3b1KbR/3rR1N1 w - -,14,636,8926,423337,6556030,318238971 -2r1k1Br/1bp1p2p/5bp1/ppP1P3/P3NB2/1PN2P1P/3K2P1/3RQ1R1 b - -,23,950,20523,851494,18603401,778787964 -1n2kr2/r1bb2np/pp2p3/1Npp1p1q/2BP1pPQ/PPP1P2P/6K1/3RB1NR w - -,37,952,32618,905188,30975060,912051177 -3N3k/5r2/1P3b1P/2n1P3/3K2p1/6P1/4b3/4R3 w - -,19,538,10070,285569,5542354,155909758 -4q1nr/1p3k1p/1N3p1b/p1ppp1p1/1P2P1P1/B1P2P1P/P2PK1BR/R2bQ1N1 w - -,7,202,6060,170730,5223606,145015774 -1b2B3/8/1k6/8/4pN2/1KP5/8/7q w - -,23,623,11654,322322,5523536,155183754 -5k2/1pr4p/7n/3ppPp1/2PB2b1/4R1P1/5NBP/2K3R1 b - -,27,1042,26905,1012187,25878795,958361771 -rnb1kbnr/ppq1ppp1/2pp4/7p/B5P1/P3P3/1PPP1P1P/RNBQK1NR b KQkq -,29,718,20965,546835,16479302,450963967 -2r5/2k4p/7P/8/3R4/8/1p1b3K/8 b - -,24,417,10339,172323,4611471,74108197 -5b2/8/8/Pk2p3/2b5/B1P1P1rp/2n5/1K5N w - -,14,490,6278,208386,2800497,89526750 -8/2n4k/1p6/8/8/1K6/5p2/6n1 b - -,19,142,2920,15458,338394,1785573 -1n1q1b1r/1b2pkpp/8/1pppPp2/rPNP2n1/pB3NP1/PBP2P2/2RQK1R1 w - -,29,1062,32357,1170099,37031836,1322995048 -3k4/7r/4K3/8/3P1R2/P6N/8/8 b - -,15,262,3683,66062,952356,17709480 -1r1qkbr1/2p1p2p/1pb2np1/p2pPB2/P1Pn4/4BP1N/1P1K2PP/RN1Q3R b - -,34,1403,46565,1888807,63497648,2555564262 -2k5/5n2/8/1K6/8/8/8/6r1 b - -,25,174,4089,20962,493956,2691085 -8/8/q4k2/p6r/PP1rp1Pp/1KnPpp2/R2N2B1/1R4N1 w - -,30,1329,36309,1585324,42328242,1837829086 -2b1q3/p2pn1p1/Prp1R3/1pP2P1k/PB1P3p/4b2P/R3K3/1NQ5 b - -,30,1340,38464,1580887,45121262,1763268603 -7r/n7/3p1npb/p1p4k/P1p1br2/5P2/1RK3BP/8 w - -,5,185,3497,127009,2309342,83162121 -r5nr/nb1p1p2/4k2b/pppR2p1/2P4P/P3KP1N/4P2P/1Q3B1R b - -,26,956,22667,762808,19547984,634817445 -1nr2k2/1r6/1p5p/p7/b1PbNp1p/4P3/5KB1/5RnR b - -,45,968,41769,1005208,41807428,1078603195 -6R1/1k5b/5P1N/7P/2pN3K/2P1p3/1r3P2/8 w - -,33,723,21611,467914,13112486,284295957 -1n1kn3/Nbb5/pp5p/3ppP2/3p1p2/PPP2K1P/4B2R/R3B1N1 b - -,17,458,8286,235179,4632247,134476813 -6n1/4k3/2P3P1/b7/7N/p4r2/r7/6K1 b - -,36,202,5981,44474,1307352,11754680 -Bnbqk3/3ppp1r/5Qp1/ppp4p/PP1b4/B3P1PP/3P1P2/RN1K2NR w - -,44,1125,46441,1264471,50499529,1436886814 -r4bnr/4pk2/4bp1p/ppppq3/PPPn2pP/N1NQ1PP1/R2P4/2B1KB1R w K -,8,306,9658,356317,11838303,431109692 -2k3r1/1b5P/p4RP1/Ppp5/1P3N2/1Pn2B1P/5K2/1rBr4 b - -,38,1404,45912,1593636,52068183,1734279409 -3k4/N4n2/PPp2b2/6p1/8/B4rN1/8/7K b - -,26,454,11363,205955,5246998,97598635 -8/P5k1/4pnp1/1p1R3p/7P/6r1/8/4bK2 w - -,19,565,10126,285162,5486899,149539969 -8/6k1/7p/1n6/3P2p1/2QK4/2P3p1/6R1 b - -,15,387,5435,155531,2181483,63895672 -rnbqkbnr/pp1p2pp/8/2p1ppB1/8/P2P4/1PP1PPPP/RN1QKBNR w KQkq -,31,821,23985,670734,19742352,577624112 -r1bqkb1r/pppppppp/2n5/1B6/3P2n1/4P3/PPP2PPP/RNBQK1NR w KQkq -,35,904,31947,823395,28884134,769148049 -1b6/k7/8/8/3K2Q1/8/6PQ/5B2 b - -,9,329,3515,129604,1298803,49668652 -4k3/8/8/3r1P2/8/8/N6p/4BK2 w - -,14,289,3838,77639,1099382,22699258 -1n3R2/3p2kp/B5p1/Pp1b2BP/P1qpPp2/5R2/5PP1/R4KN1 w - -,3,87,3288,90242,3457355,96469122 -rn3bnr/1kq1pp2/2pQ2Np/pp6/1P6/2PPPb1P/P4P2/RNB1KB2 w Q -,35,1122,38831,1259372,43220869,1429113787 -8/rb4b1/nP1p1k2/pP2pr2/2PNPPp1/B3K1P1/1R4BP/7R w - -,39,877,31864,809924,29465190,798705629 -8/8/1k6/8/8/3K3Q/6Q1/5B2 b - -,6,267,1027,46892,172313,8083615 -6N1/8/2B1Pk2/Pp3P1K/1B2b1P1/n7/7R/8 b - -,2,70,958,32722,431901,14202538 -1N6/3r4/4k3/1pK1PN2/R6P/2P2p2/8/8 w - -,29,491,11942,184205,4408234,67878536 -8/1B6/4k3/1pq5/3p4/1p6/8/5K2 w - -,14,360,4279,105537,1212767,30208208 -rnbqkbn1/ppppppp1/8/8/2P5/8/PP1PPP1r/RNBQKBNR w KQq -,21,546,13881,376773,10813645,307006307 -b3r3/1k1B4/8/3p1np1/P2P3p/8/1KQ5/8 w - -,32,664,20211,390970,11456946,222491942 -rn2qb1r/N1pkp1pp/Qp2b3/3p1P2/2PP1Pn1/7P/PP1NP3/R1B1KB1R w KQ -,31,762,25024,636665,21527061,571078834 -rn4n1/4b1kr/3pP2p/pb3p2/1P2P1pP/pKR3P1/4NP2/1N2B2R b - -,31,859,26549,758757,23538764,681225308 -8/8/1K3k2/7r/7p/p7/7b/3R4 w - -,18,432,7047,162065,2550283,59489485 -8/8/4kP1p/rpr5/1n4pP/8/1R6/6K1 w - -,17,538,8357,253881,3932585,117977134 -1n6/1b3rk1/1B4p1/1P1ppp2/2p2PpP/1p2PN2/7N/3R1R1K w - -,29,738,22015,557337,17100512,432614763 -1B6/5n2/4nk2/2B2P2/2K5/5p2/1r6/8 w - -,22,608,11051,285507,5161732,127997648 -8/2k5/P4pP1/2pr4/PNP4K/8/8/R7 w - -,21,371,7322,118160,2387637,38039638 -5R2/1k6/5P1N/7r/1Np2K2/2Pb4/3r4/8 w - -,23,655,14091,412188,8966675,263819355 -1r2kbnr/p2bp3/2qp1pp1/1pP4p/2PPN2P/4P1P1/P4P2/RNB1KB1R w KQ -,29,987,28967,1004309,29751448,1043311927 -1nb3nr/2p1p3/P1r3k1/1pP2pq1/3pP1Q1/N4KPP/P2b1P1R/1RB2BN1 b - -,39,1074,37344,1091367,38479725,1188613993 -8/3N2r1/2b1P3/r3b2P/2pk4/3Pp3/1p1R4/4K3 w - -,19,880,15233,677830,11979320,515068487 -r3qbn1/4k1pr/B4n2/1p3p1P/p1ppPP2/P1P1Q3/1P2b2P/RNB1K2R w KQ -,28,1055,30337,1145504,33824421,1291523474 -1Q6/4k3/8/3p1p2/p4p2/5bP1/3B1bP1/R4K2 w - -,37,591,19243,312435,9974634,162618911 -8/p1bpkNr1/b2B3p/3p1PpP/1rB5/P1n3R1/Q1P3P1/1R2K1N1 b - -,4,164,5434,215081,6842958,270165506 -3NN3/8/1b6/p4p2/P4Pk1/8/4r3/K7 w - -,9,224,2325,55365,607093,13972511 -4k2r/rb2b2p/p1n2pp1/2PppP1P/Q1pBP1R1/N4K2/P2P4/3R1nN1 w k -,39,1018,36747,1020037,37785535,1094321181 -rnbq1rk1/2ppn2p/1p4p1/p1b1ppB1/1PP4P/3P1R2/P2NPPP1/R2QKBN1 b Q -,30,918,28386,895569,28529291,924702995 -r2qkb1r/1p1bn1p1/2npp2p/2p2p2/Q3P2P/2PP1P1N/PP1NB1P1/R1B2K1R b kq -,35,1306,45609,1642686,57784259,2060759810 -1nq1k3/R4N2/2rP4/4KP1p/1PR5/3p1P2/4B3/2q5 w - -,36,1233,32308,1122603,28107407,999571363 -6R1/5p2/r2k4/p2rp2p/1b6/p1PN3b/R2K1PBP/8 b - -,26,778,20481,645514,17930046,577408385 -2k4r/p2n1p2/1pp1p2b/1n5p/2B2rP1/2P4K/PP6/2R3NR w - -,26,1017,26108,1020582,26927871,1050204765 -6K1/8/3r3P/8/3n3k/2p5/8/5r2 b - -,38,155,5777,24395,837731,3775907 -4kr2/3r3p/p6P/1pp1p1K1/1Pnb4/P7/R5Q1/N4B2 w - -,32,1122,32923,1107225,33372157,1094549090 -r1b1kb1r/ppp1p2p/2nq4/3p1pB1/2P1P2P/3P1K2/PP1N1PP1/R2Q1BNn b kq -,43,1268,51406,1537442,61070755,1854801758 -5k2/2Rr1N2/1p2B3/1P6/P7/5K2/7b/b7 b - -,27,771,19828,550557,14060396,380260863 -Nnb1k1nr/r1pp4/5pp1/p1b3p1/1P1p1P2/1Q2B2P/P1q1P3/2R1KBNR b Kk -,45,1313,52606,1620303,65544429,2105480167 -rn3b1r/Nqpkp1pp/pp2b2n/3p1P2/2P2P2/Q2P1N1P/PP2P3/R1B1KB1R w KQ -,38,786,29569,675114,25327035,627176843 -k7/8/8/4K3/2p5/2P3r1/8/4N3 w - -,12,176,1789,27517,291056,4665689 -1r1qkbnr/1p2pppp/1pn1b3/2p5/2PpP3/P2P2PP/1P3P2/RNB1KBNR b KQk -,28,678,19624,487367,14651136,374249525 -3N1N2/2k5/2nb2r1/8/3p4/8/8/1K3n2 b - -,35,425,12457,152426,4562577,57070496 -7R/8/1kB1P2Q/p7/1P3bp1/1K6/3q2P1/8 w - -,36,1140,31768,962135,28833323,826964746 -rnb1kb1r/pp1pp2p/2p5/q6n/P7/1QPp3n/1P1PN1KR/RNB5 b - -,36,866,29798,752154,26069237,694792963 -1rb2rk1/np1qppb1/1p3np1/2p4p/2Pp1N1P/P2PBPP1/1P1NB3/R2K3R w - -,29,896,25976,817022,23980614,774103636 -r4bnr/4pk2/3qnp1p/pppp1b1P/PPP1Q1p1/N1N2PP1/R2P2B1/2B1K2R w K -,45,1626,68227,2427928,98427662,3465347152 -8/1k3r2/4p1p1/p2nq2p/PBp4P/2r2P2/1R1R2K1/5B2 b - -,50,1163,45191,1127536,44036853,1142711427 -8/6b1/5r2/Pk2p3/7p/1KPbP1N1/1Bn5/8 w - -,13,429,5040,157837,1921415,59286441 -8/1r5n/4kbp1/BP5r/2P2p1P/p7/8/2R1N1K1 b - -,39,824,29318,646579,21686967,495383896 -7r/8/2K2Rk1/8/7p/p7/8/8 b - -,5,84,1116,18391,277597,4659085 -7k/8/4P3/6N1/P3P3/7p/N4K2/8 w - -,17,53,911,5035,85577,549523 -1r6/8/1k6/4BPpp/P6P/8/4R1KR/4q3 b - -,31,711,20777,512017,15386511,386548196 -8/4k3/Q6r/Rp1KP3/6bP/1pP2p2/3N4/2N5 w - -,33,677,21432,419043,13549927,267073347 -r7/3kN3/N7/1pK1P3/5R1P/2P2p2/8/8 w - -,28,382,9621,124569,3009021,40805021 -8/7k/3R1n1p/3p2pP/pp1P4/2Q2Kp1/2P5/6R1 w - -,35,433,14492,167388,5547231,64200051 -8/3k4/Kb6/8/2N4P/5p2/3r4/8 b - -,29,333,7693,77526,1836962,18411527 -4n1kr/7b/1pq1pbp1/p6p/1Q2BPPP/R1Bp4/1P1N4/1N3K1R w - -,40,1227,51363,1539603,65632997,1929567486 -1Qn3k1/4pb2/N7/p4P1P/3K4/7p/1R4r1/1r5n b - -,37,1213,43351,1378035,49463200,1559208584 -6nr/3bp3/Br5k/2p1P3/6pP/q2B2P1/3b1P1K/3R2NR w - -,28,1286,36219,1588037,45330228,1944065228 -5R2/8/k7/6b1/N2p2PP/3K4/6b1/8 w - -,24,457,9669,179032,3718663,68154512 -1r6/p1p3p1/2r1P1kP/P1n3P1/2Rb4/1P1b2N1/3K1N2/8 b - -,41,1039,41579,1045754,40518821,1005762480 -1rb1qbn1/ppppprp1/7k/P4P2/P1P3Pp/B6P/R2P3N/1NQ2KR1 w - -,28,457,13570,264097,8394113,186888385 -b3nbr1/k5p1/4B3/3p3p/P2P4/5n2/KR1Q4/8 b - -,23,807,18176,672612,15935458,595110713 -8/R1n5/P1p1P3/5kp1/1r6/1PB5/4KN2/b1N5 w - -,29,737,20603,495482,13689029,324694881 -8/8/1K6/1P6/6k1/6N1/8/8 b - -,6,72,407,4646,28181,319468 -6Q1/8/Pk3p2/2p5/PNP5/7K/8/R7 b - -,5,188,863,31508,146668,5279981 -Bnbqk2r/2pppp2/pp4p1/7p/PP4Q1/2b1P1P1/3P1P1P/RNB2KNR b k -,29,1201,33487,1317528,36521644,1400498960 -3k4/7p/2b4P/3p4/p1pb1B2/4r1p1/2BK1R2/7r w - -,21,861,17552,677471,14313840,528310749 -r1bqkb1r/pppppp1p/2n5/6p1/4PB2/2PP1Kn1/PP3PPP/RN1Q1BNR w kq -,34,952,28481,813248,24107615,707854547 -rnbqkbnr/1ppppppp/8/p7/2P5/7N/PP1PPPPP/RNBQKB1R b KQkq -,21,462,10715,264284,6710109,181069771 -4r2r/4p3/b4P1k/1qp2P2/5R1P/6Pp/7K/6R1 b - -,32,680,24218,540242,19983808,458976816 -2bqk2r/1p1p1pbp/r1n5/p1P1pPp1/3p4/1QN2P1N/PP2K1BP/R1B1R3 b k -,31,1260,37953,1545229,47243183,1924695821 -rn6/p2Np1rp/2pBk3/rB3p2/3b3P/8/1P3PPR/4K1R1 b - -,34,1103,35711,1116160,36785084,1129509832 -2k4n/8/8/1K6/8/8/8/6r1 w - -,8,162,890,18458,106332,2249528 -1k3r2/4K3/8/8/3P1N2/P4R2/8/8 w - -,22,290,5935,84689,1775326,26383065 -4k3/1r1bp3/3nPr2/p1Q3pP/PN6/3n1P2/4K2P/5R1R b - -,37,1430,48593,1751365,57956195,2040419691 -8/2kb4/p3Q2r/1p1KP3/2p3pP/1PPR1p2/4N3/RN6 w - -,37,730,25215,495296,17274382,343026910 -2b1kr2/1p1p1p1p/r1n5/pQP1qPb1/P2p1N2/4pP2/1P1NK1BP/R1R5 w - -,44,1718,70468,2559865,101831080,3558058064 -6nQ/3k1p1p/N3p1pb/3r3P/2p1PqP1/B4P2/P1bP1K1R/R7 b - -,46,1616,66750,2365262,93888092,3362185209 -b3r3/1k1n2r1/p1p1N1P1/Pp5P/1P4R1/1P5P/3BK1B1/1r6 b - -,31,820,23846,673950,19558807,558708721 -rnbqkb1r/p5p1/1p1pp3/2pn2pp/PP1P1P1P/7R/2PKP3/RNBQ1BN1 w kq -,31,1077,33829,1164017,37133231,1273871217 -8/3Pk3/8/2P4r/6R1/1K4p1/8/4b3 w - -,23,458,9974,198348,4257218,85754871 -3n4/k4r2/1r6/K3p3/B5p1/8/5B2/3N2b1 b - -,22,327,8764,142036,4164233,71064493 -b2r3r/3n2k1/7p/1R6/pNp4p/4PB2/5R1b/5K2 b - -,37,1372,46266,1671493,56140004,1964433873 -6k1/8/n6p/Pp1p3P/P2pPp1B/2R2R1N/b4PP1/3K4 w - -,33,522,15640,244873,7143840,112632905 -8/6b1/4KN2/p7/P7/8/3k4/8 b - -,12,169,2174,24918,334489,3757530 -8/3r4/2R5/2k5/pN3K2/Pb1P4/7r/8 b - -,2,50,1535,32217,949977,18845176 -3n4/4Bkb1/PPp2r2/6p1/8/N7/8/3K1N2 b - -,21,403,9542,193649,4853137,101312584 -8/8/3p4/K3k3/3n4/8/8/8 w - -,4,60,289,4194,22581,320001 -8/k7/1b6/1K6/B3p1p1/8/2r5/3N4 b - -,27,202,4714,54614,1258081,16847572 -6b1/3k4/4R3/N7/p2pKp2/P2P4/3r4/1r2N3 b - -,28,560,14802,301069,8104784,168654203 -r7/2b3r1/8/2p1Pb2/P1Nk3P/1p2p3/3P1R2/3K4 b - -,47,922,36407,710752,26168619,507609548 -r2qk1r1/4n2p/1pn1p3/6p1/P3P1P1/7P/3b1KbR/1r2R1N1 w - -,16,863,13395,717581,11997659,639459710 -5k2/8/8/1NP5/6B1/8/8/1K6 w - -,21,97,2015,11498,236519,1205724 -5k2/6p1/2b5/4K2R/4pP2/3q2Pn/8/1N6 b - -,38,487,15438,213530,6752634,99017418 -k7/8/8/3r4/2P3K1/8/8/8 b - -,17,117,1887,12627,208714,1419030 -rnb1k1r1/p2p1p1p/1p6/3q2p1/1bP3P1/1PNPP1Bn/P6P/R2QK1NR b KQ -,45,1194,50721,1406005,57745344,1678850376 -3n4/N3Bk2/PPp2b2/6p1/8/1r6/4N3/6K1 b - -,30,564,15863,313040,8566382,173080719 -rqb1k1r1/pp1p1p2/1N1P4/2p2PNp/4p1P1/2Q4P/PP2PKn1/R3BB1R w - -,47,959,41026,869973,35662173,808907984 -5n2/8/P2R4/k7/1p6/6nP/2B3KR/6N1 w - -,30,360,10389,131632,3687598,49598319 -r2k2nr/p1p2p1p/b3p1pb/1p1pq3/2B1P1PP/N4P2/P2P1K2/RQBR4 b - -,40,1108,42086,1198266,44215504,1309041607 -8/5k2/2P5/5p1p/8/8/4N2K/B7 b - -,8,150,987,18444,121223,2302665 -r2q2nr/p1pbkppp/2n5/bp1p2P1/3P3P/2N1P3/PPPQ1P1R/R1B1KB2 w Q -,31,970,29185,947889,28559963,952494107 -r4n2/6kp/2p4b/p2R2PP/K4p2/8/5B2/8 b - -,16,388,6334,142432,2540038,55616362 -8/8/8/4kb2/1p1p4/8/8/1B5K b - -,18,139,2115,21809,329081,3630837 -1nr3k1/7r/1p5p/p7/b1Pb1p1p/4P3/3N1KB1/5RnR w - -,25,1077,26817,1083347,28029582,1109630429 -bk6/b5r1/7p/2P4P/4p3/P1B5/3K3N/6R1 b - -,22,615,12480,335369,7130466,187137307 -rnbq1r1k/2ppn2p/1p1b2p1/P4pB1/2Pp3P/1N3R2/P3PPP1/R2QKBN1 b Q -,32,1163,35986,1316186,41949908,1556034459 -1r1q1kr1/2pBp2p/1pb3pb/p2pP3/P1PnN3/2K1BP2/1P4PP/RN1Q3R w - -,52,1569,71952,2231378,98395737,3108648708 -rnbq1bnr/6pp/Pp1kp3/2p2p2/P1p3P1/B1N2P1P/3PP1B1/R2QK1NR w KQ -,30,884,26866,815131,25834017,799405665 -3k4/3P4/8/2P5/7R/1K6/8/4b1b1 w - -,21,298,5635,84820,1583235,24946858 -8/5k2/3R1n1p/p2p2pP/1p1P2p1/6N1/2P2K1Q/R7 b - -,13,462,5173,185949,2035407,73244972 -3kn3/Nbb5/pp3n1p/3ppP2/3p1p2/PPP4P/4BK1R/R3B1N1 w - -,28,592,15483,338259,9265832,208774776 -1n2kbr1/1b5p/1B1rp3/1p4p1/pPpP1n1q/5P1P/P3P1PR/RNK2BN1 b - -,45,815,36124,695762,30429444,623209247 -b2b4/6r1/7k/8/5K2/2p5/1n6/6rn b - -,47,122,5677,18248,843803,2507492 -rnbqkbnr/p1p3pp/1p1ppp2/8/PP1P3P/8/2PKPPP1/RNBQ1BNR b kq -,26,703,18627,542851,14731988,450756403 -r1b3r1/1p6/p1kb1Q2/2p1P2p/R4pnP/1PPK1P2/4N3/1N1R4 b - -,27,1025,27333,1015782,27576525,1007238785 -2b5/2k3b1/8/1R6/8/6N1/8/N1K1b3 w - -,25,618,13162,332064,7003186,177843875 -6k1/4n3/7P/1B3K2/8/8/8/7R w - -,7,61,1521,13716,338946,2887966 -8/6k1/2B1P3/P7/8/5N2/8/2N2K2 b - -,7,189,818,21791,110957,2909616 -6k1/8/8/8/1b5B/5K2/8/1b6 w - -,14,290,3770,77483,1001196,20590454 -N2q2nr/1p4k1/8/2b2Ppp/pp4P1/B1PB1N1P/P3K3/R2q3R w - -,3,123,4060,153041,5055313,184672099 -1r4r1/1bNBb3/p1p3kp/2P1p3/1PR1Pq2/3p4/PB6/3K1RN1 b - -,45,1425,55215,1783874,65128720,2136181264 -1n1qkr2/r1bb2np/pp2p3/1Npp1p2/2B2pPQ/PPPPP2P/3B3K/3R2NR w - -,32,794,24265,656195,20625092,595068576 -5r2/q2Q1r2/5k2/p3p3/PB4pp/1PnPpP1N/1RK3P1/1N3B1R w - -,40,1156,44934,1370682,50975284,1631915257 -8/1B5k/2b4P/6R1/7K/8/8/5n2 b - -,16,355,5087,108577,1559041,32959658 -1r2rbk1/np2p3/1P3pp1/2p4p/1P3PnP/3P2Pb/1R1KB1q1/R7 b - -,36,976,36679,887761,34403946,826666301 -4n3/k7/6r1/p3p2p/2B3N1/5K2/1b5B/1N1r4 b - -,41,1046,39445,944664,34443395,814120585 -8/2k1nr2/1N6/8/3pN3/8/K2n4/8 b - -,27,451,11366,177427,4460448,65674254 -k7/bb5P/4N3/8/8/r7/3Kp3/8 w - -,16,406,5336,148843,1970560,57003807 -rnbqkbnr/ppppp1pp/5p2/8/4P3/7P/PPPP1PP1/RNBQKBNR b KQkq -,19,551,11273,334578,7545591,230382408 -1n3R2/3k4/3r3b/2pp2Pn/P7/2p4r/8/1bK2B2 b - -,36,763,24132,492030,16047573,317204254 -r1b1kb1r/pppnqpnp/3pp1p1/6N1/1P1P2P1/B3Q3/P1P1PK1P/RN3B1R b q -,25,870,23004,811256,22419570,792121026 -rnbqk2r/1p1p1pp1/p1p1pb1n/7p/8/P1NPB2P/1PP1PP2/R2QKBNR w KQkq -,32,954,28438,869646,25681141,806537286 -rR6/3k4/8/8/5P1p/p3K1b1/B7/6r1 b - -,22,527,13131,298791,7961277,177412284 -8/5k2/8/1K2P3/1N1R3P/2p2p2/8/7r w - -,26,443,11030,181877,4333781,71274238 -2B1k1n1/r1n5/2p2pr1/1pBPp3/P4P1P/N1pP4/6q1/2R1KQ1R w K -,43,1739,63721,2510256,92525277,3590381087 -r1b2bnr/2q1pk2/5p1p/ppppP3/P1Pn2pP/NPNQ1PP1/R2P4/2B1KB1R w K -,39,1370,49745,1707864,62491738,2109846027 -rnbqkbnr/p1pppp2/1p4p1/7p/8/2P1P3/PP1PBPPP/RNBQK1NR w KQkq -,29,662,20252,498704,15785475,417076322 -3b3R/1N2k3/3r4/B7/p1bp1p1N/P2P4/5K2/6r1 b - -,40,940,28107,683300,19939204,495830114 -7r/4k1B1/1p2p3/1N3b2/p4P1P/3R1B2/1P3Q2/1N4KR w - -,57,1150,62320,1199769,62445796,1214205313 -4k2r/6pp/2p1pP2/p2B1P1n/1bP5/2Np3N/2R2K1P/1r4R1 w - -,39,1249,44046,1392454,47594632,1491394368 -r1bqkbnr/pppppppp/n7/8/6Q1/4P3/PPPP1PPP/RNB1KBNR b KQkq -,20,893,19130,780737,18388507,718200429 -rnbqk1nr/pp1pppb1/2p5/6p1/8/NP1P4/P1PQPPP1/R3KBNR b KQq -,34,1139,38423,1289227,43685127,1479697105 -1B6/3R2b1/2r1knp1/5p1r/pP5P/2P1NK2/4n3/2R5 b - -,33,1224,39842,1372259,44887534,1487479617 -bbn1N2r/8/1q6/p2P3k/2P1BP1p/4P3/PB1K4/2R4r w - -,39,1552,51325,1985018,64054450,2460343166 -rnbqkbnr/ppppp1pp/8/5p2/8/1PN5/P1PPPPPP/R1BQKBNR b KQkq -,20,459,10239,258319,6302413,171094418 -8/3NbB2/P1R3P1/7k/3p3P/8/K5N1/4r3 b - -,24,671,13649,382464,7548425,215070303 -8/8/8/1p2k3/3p4/1p6/6B1/5K2 b - -,8,95,876,11946,118080,1553341 -rnbqkb1r/p3n1p1/1p1ppp2/2p3Pp/PP1P1P1P/8/2PKP3/RNBQ1BNR b kq -,29,820,23938,711215,21084888,653127533 -4N3/8/5P2/p2K4/Pb6/7r/8/5k2 w - -,10,268,2678,67109,731926,17708947 -8/5Q1b/4p2k/4P2p/1p2P1BP/8/8/2NK4 w - -,33,167,4972,32984,926688,7750939 -8/1n6/P1p1k3/4b1pR/1P6/N5N1/3BKr2/8 w - -,5,164,4367,129359,3553310,98908977 -rnb1qbkr/3pp3/p7/2p2p1p/P1pP1Np1/4P3/NPK2PPP/R1Q2B1R w - -,32,694,22835,562837,18992767,509635868 -5n2/5k1p/r1p4P/p6P/K4p2/3R4/8/4B3 b - -,13,298,4178,84638,1305743,25873951 -8/1p2k2B/7n/3r2p1/3p4/KRpb2PN/7P/5R2 w - -,34,1007,31084,876009,26592956,725172694 -8/1P4P1/5k2/3b4/r2p4/3P3K/8/Q1RN4 w - -,31,808,26667,613386,21930297,469048771 -1n6/p6k/P4P2/1pqp2p1/3P3p/2B4P/5NR1/4Q1K1 w - -,32,610,20073,411603,13453446,280742958 -rnbk1r2/3p3p/2p3q1/p1bN4/PP2Q1n1/3p3n/1R1P3R/2B4K b - -,51,1639,75377,2437669,109127468,3534792980 -rn6/1b2k1b1/1P1p4/pP2pr2/2PpPPp1/BN4P1/3K2BP/1R5R w - -,36,1064,36170,1060512,35072270,1034288751 -5n1k/8/2B3p1/4p2p/7P/b7/7K/8 w - -,16,222,3090,47479,629762,10203927 -2k3n1/8/8/8/8/4N3/3N4/3K4 b - -,8,136,1349,22923,236071,4039840 -2b1k3/4p1rp/1r1nP3/p1p3p1/1P3nP1/PQNP1P2/5K1P/5R1R w - -,34,1152,35954,1179405,37546427,1206791550 -2k1N3/8/2b5/2B4r/8/8/8/b3K3 b - -,34,601,19232,315549,9939713,159829189 -k7/7r/8/8/2pK4/2P5/4N3/8 b - -,17,151,2472,25505,417948,4367315 -7k/4r2B/8/P4K2/1p3b2/2R4p/4N3/8 b - -,29,679,16516,379628,8729367,199714373 -r3r3/pb1k4/P6B/2PPb3/1PB1n1q1/6P1/1P5P/1N2KR2 b - -,52,1471,67576,1849276,82821318,2284504952 -8/r7/4N2k/pN3p2/P1K2P2/6p1/8/8 w - -,19,230,3891,51626,844194,12128561 -1b2k2b/8/1p5N/PP6/4K3/8/1R6/5B2 b - -,18,458,8881,224044,4335435,109314467 -8/4kb2/3B3P/P1K1P3/6P1/8/8/8 b - -,4,51,493,7098,75497,1129213 -2b5/8/2n2rk1/3p1p2/Pp3PPp/1P5P/2K5/6Rn w - -,18,394,6396,148009,2328769,55937023 -1rbqkbr1/p2p2pn/1p2p3/2n4p/PP1P4/2p3PP/R1P1P3/1NBQKBNR b K -,31,827,26459,719963,23637490,673985658 -2k5/4B2Q/3pp3/7P/2pPn2b/8/8/K1R4B b - -,20,633,10062,349593,5356539,193509469 -rn1qk1nr/p1pp2pp/b2b1p2/1p2p3/4P1P1/1QPK3P/PP1P1P2/R1B2BNR b kq -,22,571,12383,322729,7636084,203091517 -1n3r1k/1bqpP2p/Bp4p1/P5BP/3pPp2/5R2/P4PP1/R2K2N1 b - -,34,1273,39650,1479078,46064822,1714541478 -6nr/1pq1bk2/8/4p1pp/ppN1BPP1/B1P4P/P2pK3/5RNR w - -,42,1364,49686,1719296,59415902,2124421947 -rn2kbnr/p3q1p1/2ppbp2/P3p2p/Rp2PB2/1P1P2PP/2PN1P2/Q3KBNR w Kkq -,33,993,33197,994766,33777199,1028646924 -r1bn1r2/2k3p1/6p1/pP3p2/4P2P/1P1PBR1q/2P1N1p1/Q3K3 w - -,47,1384,53146,1648415,60262481,1952220550 diff --git a/src/BBmacros.cpp b/src/BBmacros.cpp deleted file mode 100644 index 1b27503..0000000 --- a/src/BBmacros.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "BBmacros.h" -#include - -void printBitBoard(BitBoard bitboard) { - // loop over board ranks - for (int rank = 0; rank < 8; rank++) { - std::cout << 8 - rank << " "; - for (int file = 0; file < 8; file++) { - Square square = rank * 8 + file; - std::cout << (int)testBit(bitboard, square) << " "; - } - std::cout << "\n"; - } - std::cout << "\n a b c d e f g h\n\n"; -} diff --git a/src/BBmacros.h b/src/BBmacros.h deleted file mode 100644 index 347d51a..0000000 --- a/src/BBmacros.h +++ /dev/null @@ -1,181 +0,0 @@ -// The BBmacros.h and BBmacros.cpp files contain utility definitions to write some more readable code -#pragma once -#include -#include - - -#include - -#ifdef _MSC_VER -#include -#endif - -#include "types.h" -#include "constants.h" - -inline constexpr BitBoard squareBB(Square square) { return (1ULL << square); } -inline U64 getBit(BitBoard bitboard, Square square) { return (bitboard & squareBB(square)); } -inline U8 testBit(BitBoard bitboard, Square square) { return (getBit(bitboard, square) > 0); } -inline void setBit(BitBoard& bitboard, Square square) { bitboard |= squareBB(square); } -inline void clearBit(BitBoard& bitboard, Square square) { bitboard &= (~squareBB(square)); } -inline void clearBit(U8 &u8, U8 pos) { u8 &= ~(1 << pos); } - -inline U8 rankOf(Square square) { return (square >> 3); } -inline U8 fileOf(Square square) { return (square & 7); } -inline Square flipSquare(Square square) { return (square ^ 56); } -inline Square flipSquareHorizontal(Square square) { return (square ^ 7); } -inline Square makeSquare(U8 rank, U8 file) { return (rank * 8 + file); } - -inline constexpr BitBoard files(U8 fileNo) { return (0x0101010101010101ULL << fileNo); } -inline constexpr BitBoard ranks(U8 rankNo) { return (0xFFULL << (rankNo<<3)); } -inline constexpr BitBoard notFile(U8 fileNo) { return ~files(fileNo); } -inline constexpr BitBoard notRank(U8 rankNo) { return ~ranks(rankNo); } -inline constexpr BitBoard squaresAhead(Square square) { return (files(7) ^ 0x8000000000000000) >> (63 - square); } -inline constexpr BitBoard squaresBehind(Square square) { return (files(0) ^ 0x1ULL) << square; } -constexpr BitBoard squaresOfColor[2] = { 0xAA55AA55AA55AA55ULL, 0x55AA55AA55AA55AAULL }; - -static inline constexpr BitBoard ne(BitBoard bb) { return (bb & notFile(7)) >> 7; } -static inline constexpr BitBoard north(BitBoard bb) { return bb >> 8; } -static inline constexpr BitBoard nw(BitBoard bb) { return (bb & notFile(0)) >> 9; } -static inline constexpr BitBoard se(BitBoard bb) { return (bb & notFile(7)) << 9; } -static inline constexpr BitBoard south(BitBoard bb) { return bb << 8; } -static inline constexpr BitBoard sw(BitBoard bb) { return (bb & notFile(0)) << 7; } -static inline constexpr BitBoard east(BitBoard bb) { return (bb & notFile(7)) << 1; } -static inline constexpr BitBoard west(BitBoard bb) { return (bb & notFile(0)) >> 1; } - -static inline constexpr S32 indexColorKingsKingside(U8 color, U8 sameside, U8 side) {return (color << 2) + (sameside << 1) + side; } - -#define bitScanForward _BitScanForward64 //ls1b -#define bitScanReverse _BitScanReverse64 //ms1b -#define makeSquareColor(color,square) (((color) * 64) + (square)) - -#define emptyBoard "8/8/8/8/8/8/8/8 w - - " -#define startPosition "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 " -#define trickyPosition "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq e8 0 1 " -#define killerPosition "rnbqkb1r/pp1p1pPp/8/2p1pP2/1P1P4/3P3P/P1P1P3/RNBQKBNR w KQkq e6 0 1" -#define cmkPosition "r2q1rk1/ppp2ppp/2n1bn2/2b1p3/3pP3/3P1NPP/PPP1NPB1/R1BQ1RK1 b - - 0 9 " - - -// The squares name -const std::string coords[65] = { - "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", - "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", - "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", - "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", - "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", - "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", - "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", - "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", "noSquare" -}; - -/** - * @brief The printBitBoard function prints a bitboard. - * @notes For debugging purposes. - */ -void printBitBoard(BitBoard bitboard); - -#if defined(__GNUC__) // GCC, Clang, ICC - -inline Square lsb(BitBoard b) { - assert(b); - return Square(__builtin_ctzll(b)); -} - -inline Square msb(BitBoard b) { - assert(b); - return Square(63 ^ __builtin_clzll(b)); -} - -inline int popcount(BitBoard b) { - return __builtin_popcountll(b); -} - -inline BitBoard reflectBitBoard(BitBoard bb) { return __builtin_bswap64(bb); } - -#elif defined(_MSC_VER) // MSVC - -#ifdef _WIN64 // MSVC, WIN64 - -inline Square lsb(BitBoard b) { - assert(b); - unsigned long idx; - _BitScanForward64(&idx, b); - return (Square)idx; -} - -inline Square msb(BitBoard b) { - assert(b); - unsigned long idx; - _BitScanReverse64(&idx, b); - return (Square)idx; -} - -inline int popcount(BitBoard b) { - return (int)__popcnt64(b); -} - -inline BitBoard reflectBitBoard(BitBoard bb) { return _byteswap_uint64(bb); } - -#else // MSVC, WIN32 - -inline Square lsb(BitBoard b) { - assert(b); - unsigned long idx; - - if (b & 0xffffffff) { - _BitScanForward(&idx, int32_t(b)); - return Square(idx); - } - else { - _BitScanForward(&idx, int32_t(b >> 32)); - return Square(idx + 32); - } -} - -inline Square msb(BitBoard b) -{ - assert(b); - unsigned long idx; - - if (b >> 32) { - _BitScanReverse(&idx, int32_t(b >> 32)); - return Square(idx + 32); - } - else { - _BitScanReverse(&idx, int32_t(b)); - return Square(idx); - } -} - -#endif - - -#else // Compiler is neither GCC nor MSVC compatible - -#error "Compiler not supported." - -#endif - -/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard - -inline Square popLsb(BitBoard& b) { - assert(b); - const Square s = lsb(b); - b &= b - 1; - return s; -} - -inline void prefetch(void* addr) { - -# if defined(__INTEL_COMPILER) - // This hack prevents prefetches from being optimized away by - // Intel compiler. Both MSVC and gcc seem not be affected by this. - __asm__(""); -# endif - -# if defined(__INTEL_COMPILER) || defined(_MSC_VER) - _mm_prefetch((char*)addr, _MM_HINT_T0); -# else - __builtin_prefetch(addr); -# endif -} \ No newline at end of file diff --git a/src/Game.cpp b/src/Game.cpp deleted file mode 100644 index 1af1dbf..0000000 --- a/src/Game.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "Game.h" -#include "constants.h" -#include "uci.h" -#include "tt.h" -#include "history.h" -#include "movegen.h" -#include "tables.h" -#include "evaluation.h" -#include -#include -#include -#include -#include - -/** - * @brief The perft function calculates the number of leaf nodes in the subtree rooted at the current position. - * @param depth The depth to calculate to. - * @return The number of leaf nodes in the subtree rooted at the current position. - */ -U64 Game::perft(Depth depth){ - //std::cout << "Starting perft at depth " << depth << std::endl; - nodes = 0; - return _perft(depth); -} - -/** - * @brief The divide function calculates the number of leaf nodes in the subtree rooted at the current position. - * It shows the number of nodes for each possible move in the current position. - * @param depth The depth to calculate to. - * @return The number of leaf nodes in the subtree rooted at the current position. - */ -U64 Game::divide(Depth depth) { - std::cout << "Starting divide at depth " << (int)depth << std::endl; - // Get time - auto start = getTime64(); - nodes = 0; - MoveList moveList; - pos.generateUnsortedMoves(moveList); - UndoInfo undoer = UndoInfo(pos); - - for (int i = 0; i < moveList.count; i++) { - if (pos.makeMove(moveList.moves[i])) { - printMove(moveList.moves[i]); - std::cout << moveList.moves[i] << "\t" << ": " << std::flush; - U64 res = _perft(depth - 1); - nodes += res; - std::cout << res; - std::cout << std::endl; - undoer.undoMove(pos, moveList.moves[i]); - } - else { - undoer.undoMove(pos, moveList.moves[i]); - } - } - auto end = getTime64(); - - std::cout << "Divide results: " << nodes << "\n" - << "Time: " << (end - start) << " ms\n" - << "nps: " << std::to_string((nodes * 1000) / (end - start)) << std::endl; - return nodes; -} - -void Game::communicate() { - UCICommunicate(this); -} - -/** - * @brief The _perft function calculates the number of leaf nodes in the subtree rooted at the current position. - * @param depth The depth to calculate to. - * @return The number of leaf nodes in the subtree rooted at the current position. - * @note This function is used by the perft function. - */ -U64 Game::_perft(Depth depth) { - if (depth <= 0) { - return 1; - } - U64 n = 0; - MoveList moveList; - pos.generateUnsortedMoves(moveList); - UndoInfo undoer = UndoInfo(pos); - ++ply; - for (int i = 0; i < moveList.count; i++) { - if (pos.makeMove(moveList.moves[i])) { - n += _perft(depth - 1); - undoer.undoMove(pos, moveList.moves[i]); - } - else { - undoer.undoMove(pos, moveList.moves[i]); - } - } - --ply; - return n; -} - -/** - * @brief The reset function resets the game. - */ -void Game::reset(){ - pos.parseFEN((char*)std::string(startPosition).c_str()); - depth = 0; - moveTime = 0; - wtime = 0; - btime = 0; - winc = 0; - binc = 0; - stopped = false; - lastScore = 0; - ply = 0; - seldepth = 0; - rootDelta = infinity; - nmpPlies = 0; - age = 0; - - // Clear history, killer and counter move tables - memset(historyTable, 0, sizeof(historyTable)); - memset(counterMoveTable, 0, sizeof(counterMoveTable)); - memset(captureHistoryTable, 0, sizeof(captureHistoryTable)); - memset(continuationHistoryTable, 0, sizeof(continuationHistoryTable)); - memset(pawnsCorrHist, 0, sizeof(pawnsCorrHist)); - memset(nonPawnsCorrHist, 0, sizeof(nonPawnsCorrHist)); - memset(tripletCorrHist, 0, sizeof(tripletCorrHist)); - - - // Clear pv len and pv table - memset(pvLen, 0, sizeof(pvLen)); - memset(pvTable, 0, sizeof(pvTable)); - - // Clear hashTable -#if ENABLETTSCORING - // tt is a vector, so we can't use memset. We have to clear it manually. - for (size_t i = 0; i < tt.size(); i++) { - tt[i].hashKey = 0; - tt[i].bestMove = 0; - tt[i].depth = 0; - tt[i].score = noScore; - tt[i].eval = noScore; - tt[i].agePvFlag = hashNONE; - } - - // Clear pawn hash table - memset(pawnEvalHash, 0, sizeof(pawnEvalHash)); -#endif - -} - -/** - * @brief The parseFEN function parses a FEN string, and places the pieces on the board. It also sets the turn, castling rights, en passant square, half move clock and full move number. - * It is filled with sanity checks, and will print an error message containing the error if it finds one. - * @param fen The FEN string to parse. - * @return True if the FEN string was parsed successfully, false otherwise (state of the position is undefined). - * @note This function is a call to the Position::parseFEN function. - */ -bool Game::parseFEN(char *FEN){ - return pos.parseFEN(FEN); -} - -/** - * @brief The executeMoveList function executes a list of moves. - * @param moveList The char* to the list of moves to execute. - * @return True if the move list was executed successfully, false otherwise (state of the position is undefined). - */ -bool Game::executeMoveList(char *moveList){ - - std::stringstream ss(moveList); - std::string move; - - while (ss >> move) { - Move parsedMove = getLegal(move.c_str()); - repetitionTable[pos.totalPly] = pos.hashKey; - if (!pos.makeMove(parsedMove)) return false; - } - - return true; -} - -/** - * @brief The getLegal function returns a move from a string. It returns 0 if the move is not legal. - * @param move The string to parse. - * @return The move parsed from the string. - */ -Move Game::getLegal(std::string move){ - MoveList moveList; - pos.generateUnsortedMoves(moveList); - for (int i = 0; i < moveList.count; i++) { - if (move == getMoveString(moveList.moves[i])) { - return (Move)moveList.moves[i]; - } - } - std::cout << "Not found!\n"; - return 0; -} - -/** - * @brief The print function prints the current position. - * @note This function is a call to the internal Position::print function. - */ -void Game::print(){ - pos.print(); -} - -/** - * @brief The generateMoves function generates all pseudo legal moves for the current position. It is a call to the internal Position::generateMoves function. - * @param moves The MoveList object to store the moves in. - * @param killer1 The first killer move. - * @param killer2 The second killer move. - * @param counterMove The counter move. - */ -void Game::generateMoves(MoveList &moves, SStack* ss){ - pos.generateMoves(moves, ss); - // We will sort the moves - std::sort(std::begin(moves.moves) + 1, std::begin(moves.moves) + moves.count, std::greater()); -} - -/** - * @brief The generateCaptures function generates all pseud legal captures for the current position. It is a call to the internal Position::generateCaptures function. - * @param moves The MoveList object to store the moves in. - */ -void Game::generateCaptures(MoveList &moves){ - pos.generateCaptures(moves); - // We will sort the moves - std::sort(std::begin(moves.moves) + 1, std::begin(moves.moves) + moves.count, std::greater()); -} - -/** - * @brief The makeMove function makes a move on the board. It is a call to the internal Position::makeMove function. - * @param move The move to make. - * @return True if the move was made, false otherwise (state of the position is undefined). - */ -bool Game::makeMove(Move move){ - assert(pos.totalPly >= 0); - assert(pos.totalPly >= pos.fiftyMove); - assert(pos.totalPly <= std::numeric_limits::max()); - ++ply; -#if DETECTREPETITION - repetitionTable[pos.totalPly] = pos.hashKey; -#endif - bool k = pos.makeMove(move); - return k; -} - -/** - * @brief The isRepetition function returns true if the current position is a repetition. - * @return True if the current position is a repetition, false otherwise. - */ -bool Game::isRepetition() { - assert(pos.totalPly >= pos.fiftyMove); - // Get the hash key of the current position - S32 dist = std::min((S32)pos.fiftyMove, (S32)pos.plyFromNull); - HashKey hashKey = pos.hashKey; - S32 startPoint = pos.totalPly; - S32 counter = 0; - for (int idx = 4; idx <= dist; idx += 2){ - if (repetitionTable[startPoint - idx] == hashKey) { - if (idx < ply) return true; - if (++counter >= 2) return true; - } - } - return false; -} - -/** - * @brief The eval function evaluates the current position. - * @return The static evaluation of the current position. - */ -Score Game::evaluate(){ - const auto matScaleValues = - popcount(pos.bitboards[N] | pos.bitboards[B] | pos.bitboards[n] | pos.bitboards[b]) * pieceValues[N] - + popcount(pos.bitboards[R] | pos.bitboards[r]) * pieceValues[R] - + popcount(pos.bitboards[Q] | pos.bitboards[q]) * pieceValues[Q]; - - return pestoEval(&pos) * (27075 + matScaleValues) / 32768; -} - -void Game::makeNullMove() { - ++ply; - repetitionTable[pos.totalPly] = pos.hashKey; - pos.makeNullMove(); -} - -void Game::undo(UndoInfo& undoer, Move move) { - --ply; - undoer.undoMove(pos, move); -} - -void Game::undoNullMove(UndoInfo& undoer) { - --ply; - undoer.undoNullMove(pos); -} \ No newline at end of file diff --git a/src/Game.h b/src/Game.h deleted file mode 100644 index 8d7f7e2..0000000 --- a/src/Game.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once -#include "Position.h" -#include "history.h" - -extern S64 seCandidates; -extern U64 seActivations; -extern S64 avgDist; - -class Game { -public: - U64 nodes = 0; - U64 hardNodesLimit = 0; - Ply ply; - Position pos; - Depth depth; - Depth currSearch; - U16 seldepth = 0; - U64 moveTime; - U8 searchMode = 0; - U32 wtime; - U32 btime; - U32 winc; - U32 binc; - S32 rootDelta = infinity; - Score lastScore = 0; - U64 nodesPerMoveTable[64 * 64]; - S16 nmpPlies = 0; - bool stopped = false; - U8 age = 0; - - /** - * @brief The print function prints the position to stdout. - */ - void print(); - - /** - * @brief The perft function calculates the number of leaf nodes in the subtree rooted at the current position. - * @param depth The depth to calculate to. - * @return The number of leaf nodes in the subtree rooted at the current position. - */ - U64 perft(Depth _depth); - - /** - * @brief The _perft function calculates the number of leaf nodes in the subtree rooted at the current position. - * @param depth The depth to calculate to. - * @return The number of leaf nodes in the subtree rooted at the current position. - * @note This function is used by the perft function. - */ - U64 _perft(Depth _depth); - - /** - * @brief The divide function calculates the number of leaf nodes in the subtree rooted at the current position. - * It shows the number of nodes for each possible move in the current position. - * @param depth The depth to calculate to. - * @return The number of leaf nodes in the subtree rooted at the current position. - */ - U64 divide(Depth depth); - - /** - * @brief The reset function resets the game. - */ - void reset(); - - /** - * @brief The parseFEN function parses a FEN string, and places the pieces on the board. It also sets the turn, castling rights, en passant square, half move clock and full move number. - * It is filled with sanity checks, and will print an error message containing the error if it finds one. - * @param fen The FEN string to parse. - * @return True if the FEN string was parsed successfully, false otherwise (state of the position is undefined). - * @note This function is a call to the Position::parseFEN function. - */ - bool parseFEN(char* FEN); - - /** - * @brief The executeMoveList function executes a list of moves. - * @param moveList The char* to the list of moves to execute. - * @return True if the move list was executed successfully, false otherwise (state of the position is undefined). - */ - bool executeMoveList(char* moveList); - - /** - * @brief The getLegal function returns a move from a string. It returns 0 if the move is not legal. - * @param move The string to parse. - * @return The move parsed from the string. - */ - Move getLegal(std::string move); - - /** - * @brief The generateMoves function generates all pseudo legal moves for the current position. It is a call to the internal Position::generateMoves function. - * @param moves The MoveList object to store the moves in. - * @param ss The SStack object to get the search information from (useful for move ordering heuristics). - */ - void generateMoves(MoveList& moves, SStack* ss); - - /** - * @brief The generateCaptures function generates all pseud legal captures for the current position. It is a call to the internal Position::generateCaptures function. - * @param moves The MoveList object to store the moves in. - */ - void generateCaptures(MoveList &move); - - /** - * @brief The makeMove function makes a move on the board. It is a call to the internal Position::makeMove function, but it also updates the repetition table, as well as the ply. - * @param move The move to make. - * @return True if the move was made, false otherwise (state of the position is undefined). - */ - bool makeMove(Move move); - - /** - * @brief The isRepetition function returns true if the current position is a repetition. - * @return True if the current position is a repetition, false otherwise. - */ - bool isRepetition(); - - /** - * @brief The eval function evaluates the current position. - * @return The static evaluation of the current position. - */ - Score evaluate(); - - /** - * @brief The search function is the main routine for the engine search - * @param alpha The lower bound of the search - * @param beta The upper bound of the search - * @param depth The depth to the quiescence drop - * @param cutnode If true, the node is expected to be a cut node - * @param ss The SStack object to store the search information in - * @return The score of the position - */ - Score search(Score alpha, Score beta, Depth depth, bool cutnode, SStack* ss); - - /** - * @brief The makeNullMove function makes a null move on the board. - * @note This function is a call to the internal Position::makeNullMove function, but it will update repetition informatio, as well as the ply; - */ - void makeNullMove(); - - /** - * @brief The undo function undoes a move on the board. - * @param undoer The UndoInfo object to store the information in. - * @param move The move to undo. - * @note Do not use this function to undo a null move. - */ - void undo(UndoInfo &undoer, Move move); - - /** - * @brief The undoNullMove function undoes a null move on the board. - * @param undoer The UndoInfo object to store the information in. - * @note This function is a call to the internal Position::undoNullMove function, but it will update repetition information, as well as the ply. - */ - void undoNullMove(UndoInfo &undoer); - - /** - * @brief The quiescence function takes the leaves of the negamax tree and expands them up until no immediate tactical moves are available. - * @param alpha The lower bound of the search - * @param beta The upper bound of the search - * @param ss The SStack object to store the search information in - * @return The score of the position. - */ - Score quiescence(Score alpha, Score beta, SStack* ss); - - /** - * @brief The startSearch function starts the search. It uses the internal parameters set by the GUI. - * @param ageTT If true, the game age will be increased by one at the start of the search, making previous entries old. - */ - void startSearch(bool ageTT); - - /** - * @brief The contempt function returns the contempt score. The contempt score is used to assign a non-zero score to draw positions, depending on the optimism of the engine. - * @return The contempt score. - */ - Score contempt(); - - /** - * @brief The communicate function communicates with the GUI. - * @note This is a call to the uci communicate(Game) function. - */ - void communicate(); -}; - diff --git a/src/Perseus.cpp b/src/Perseus.cpp deleted file mode 100644 index 4cccc86..0000000 --- a/src/Perseus.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "uci.h" -#include "tables.h" -#include "bench.h" -#include "evaluation.h" -#include "history.h" -#include -#include -#include -#include -#include - -void split(std::string s, std::string delim, std::vector & v){ - size_t pos = 0; - std::string token; - while ((pos = s.find(delim)) != std::string::npos) { - token = s.substr(0, pos); - v.push_back(token); - s.erase(0, pos + delim.length()); - } - v.push_back(s); -} - -void perftSuite(){ - Game g; - // Open the perft suite file - std::ifstream perftFile("../perft.txt"); - std::vector failed; // The perft not passed - std::string line; - int cnt = 0; - U64 totNodes = 0; - while (std::getline(perftFile, line)) { - // Read the fen - std::string fen = line.substr(0, line.find(",")); - // Read the perft results - std::string perftResults = line.substr(line.find(",") + 1); - // Parse the perft results - std::vector perftResultsVector; - split(perftResults, ",", perftResultsVector); - // Parse the fen - g.parseFEN((char*)fen.c_str()); - // Run the perft tests (ONLY if target perft is less than 100000000) - for (size_t i = 0; i < perftResultsVector.size(); i++) { - if (i > 5) { - break; - } - U64 target = U64(atoll(perftResultsVector[i].c_str())); - if (target < 100000000LL) { - std::cout << "\rPerft " << (int)cnt << " depth " << (int)i + 1 << ": " << (int)target << " nodes"; - U64 result = g.perft(i + 1); - totNodes += result; - if (result != target) { - std::cout << " Failed."; - failed.push_back(fen + "," + perftResultsVector[i]); - } - } - } - cnt++; - std::cout << "\n\n" << std::endl; - std::cout << "=== Summary ===\n"; - std::cout << "Passed : " << (cnt - failed.size()) << " / " << cnt<< "\n"; - std::cout << "Failed : " << failed.size() << " / " << cnt << "\n"; - std::cout << "Total nodes : " << totNodes << std::endl; - } - - std::ofstream failedFile("failed.txt"); - for (size_t i = 0; i < failed.size(); i++) { - failedFile << failed[i] << "\n"; - } - failedFile.close(); - perftFile.close(); - std::cout << "Perft suite completed.\n"; -} - -int main(int argc, char* argv[]){ - initAll(); - // perftSuite(); - Game game; - - // Check if the first argument is "bench" - if (argc > 1){ - if (std::string(argv[1]) == "bench") { - // If the second argument is provided, parse it; otherwise, use the default value 12 - int depth = (argc > 2) ? std::atoi(argv[2]) : 12; - benchmark(depth); - return 0; - } - else if (std::string(argv[1]) == "extract") { - // If the second argument is provided, parse it; otherwise, return error - if (argc < 3) { - std::cerr << "Usage " << argv[0] << " extract \n"; - return 1; - } - std::string inputFilename(argv[2]); - std::string outputFilename; - - // Find the last '.' in the filename - size_t dotPos = inputFilename.find_last_of('.'); - - if (dotPos != std::string::npos) { - // If there's an extension, replace it with ".feat" - outputFilename = inputFilename.substr(0, dotPos) + ".feat"; - } else { - // If no extension, just add ".feat" - outputFilename = inputFilename + ".feat"; - } - convertToFeatures(inputFilename, outputFilename); - return 0; - } - } - uciLoop(&game); - return 0; -} diff --git a/src/Position.cpp b/src/Position.cpp deleted file mode 100644 index 26ea60d..0000000 --- a/src/Position.cpp +++ /dev/null @@ -1,1798 +0,0 @@ -#include "Game.h" -#include "movegen.h" -#include "tables.h" -#include "history.h" -#include "evaluation.h" -#include "zobrist.h" -#include -#include - -unsigned long long BADCAPTURESCORE = MAXHISTORYABS - 424ULL; // TODO: make this tunable - -// The default constructor instantiates the position with the standard chess starting position. -Position::Position(){ - parseFEN((char*)std::string(startPosition).c_str()); -} - -// The FEN constructor instantiates the position with the FEN string. -Position::Position(const char* fen){ - parseFEN((char*)fen); -} - -/** - * @brief The Position::generateHashKey function generates the hash key of the position from scratch. - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ -HashKey Position::generateHashKey() { - HashKey h = 0ULL; - for (int i = Pieces::P; i <= Pieces::k; i++) { - BitBoard pieceBB = bitboards[i]; - while (pieceBB) { - Square square = popLsb(pieceBB); - h ^= pieceKeysTable[i][square]; - } - } - h ^= enPassantKeysTable[enPassant]; - h ^= castleKeysTable[castle]; - if (side == Side::BLACK) h ^= sideKey; - return h; -} - -/** - * @brief The Position::generatePawnHashKey function generates the hash key of the pawn structure from scratch. - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ -HashKey Position::generatePawnHashKey() { - HashKey h = 0ULL; - for (int i = Pieces::P; i <= Pieces::k; i += 6) { - BitBoard pieceBB = bitboards[i]; - while (pieceBB) { - Square square = popLsb(pieceBB); - h ^= pawnKeysTable[i][square]; - } - } - h ^= enPassantKeysTable[enPassant]; - return h; -} - -/** - * @brief The Position::generateNonPawnHashKey function generates the hash key of the non pawn structure from scratch, for a given side. - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ -HashKey Position::generateNonPawnHashKey(const bool side) { - const S32 offset = side ? 6 : 0; - HashKey h = 0ULL; - for (int i = Pieces::N + offset ; i <= Pieces::K + offset; i++) { - BitBoard pieceBB = bitboards[i]; - while (pieceBB) { - Square square = popLsb(pieceBB); - h ^= nonPawnKeysTable[i][square]; - } - } - return h; -} - -/** - * @brief The Position::generatePtHashKey function generates the hash key for a single pt from scratch. - * @tparam The pt to generate - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ -template -HashKey Position::generatePtHashKey(){ - HashKey h = 0ULL; - for (int i = pt; i <= Pieces::k; i += 6) { - BitBoard pieceBB = bitboards[i]; - while (pieceBB) { - Square square = popLsb(pieceBB); - h ^= pieceKeysTable[i][square]; - } - } - return h; -} - -/** - * @brief The Position::print function prints the position to stdout. - */ -void Position::print(){ - std::cout << "\n"; - for(int rank = 0; rank < 8; rank++){ - std::cout << 8 - rank << " "; - for(int file = 0; file < 8; file++){ - Square square = rank * 8 + file; - for (int piece = Pieces::P; piece <= Pieces::k; piece++){ - if (testBit(bitboards[piece], square)){ - std::cout << getPieceChar(piece); - goto NEXT; - } - } - std::cout << "."; - - NEXT: std::cout << " "; - } - std::cout << "\n"; - } - std::cout << "\n a b c d e f g h\n\n"; - std::cout << "Side:\t\t\t" << ((side == WHITE)? "WHITE" : "BLACK") << "\n"; - std::cout << "En passant:\t\t" << coords[enPassant] << "\n"; - std::cout << "Castle:\t\t\t" << - ((castle & CastleRights::WK) ? "K" : "") << - ((castle & CastleRights::WQ) ? "Q" : "") << - ((castle & CastleRights::BK) ? "k" : "") << - ((castle & CastleRights::BQ) ? "q" : "") << "\n"; - std::cout << "Hash:\t\t\t" << std::hex << hashKey << std::dec << "\n"; - std::cout << std::endl; - -} - -/** - * @brief The wipe function wipes the position. - */ -void Position::wipe(){ - for(int piece = Pieces::P; piece <= Pieces::k; piece++){ - bitboards[piece] = 0; - } - occupancies[WHITE] = occupancies[BLACK] = occupancies[BOTH] = 0; - side = Side::WHITE; - enPassant = 0; - fiftyMove = 0; - totalPly = 0; - plyFromNull = 0; - castle = 0; - hashKey = 0; - pawnHashKey = 0; - nonPawnKeys[0] = nonPawnKeys[1] = 0; - memset(ptKeys,0,sizeof(ptKeys)); - memset(psqtScores,0,sizeof(psqtScores)); -} - -/** - * @brief The addPiece function removes a piece from the board. It also incrementally updates psqt and various hash keys - * @tparam unsafe Set it to true if we are removing a piece that we are sure is there - * @param pos the Position object to update - * @param square The square where the piece is. - * @param piece The piece to remove. - */ -template -static inline void removePiece(Position& pos, const Piece piece, const Square square){ - const auto pieceSide = piece >= p; - if constexpr (!unsafe){ - // Remove the piece from the bitboard - clearBit(pos.bitboards[piece], square); - // Add it also to the side and both bitboard - clearBit(pos.occupancies[pieceSide], square); - clearBit(pos.occupancies[BOTH], square); - } - else { - const BitBoard sqb = squareBB(square); - pos.bitboards[piece] ^= sqb; - pos.occupancies[pieceSide] ^= sqb; - pos.occupancies[BOTH] ^= sqb; - } - // Update the hash key - pos.hashKey ^= pieceKeysTable[piece][square]; - pos.pawnHashKey ^= pawnKeysTable[piece][square]; - pos.nonPawnKeys[pieceSide] ^= nonPawnKeysTable[piece][square]; - pos.ptKeys[piece - 6 * (pieceSide)] ^= pieceKeysTable[piece][square]; - // Update the psqt score - // Same side kings, own king on right (flip square) - pos.psqtScores[indexColorKingsKingside(pieceSide, 0, 0)] -= PSQTs[0][piece][flipSquareHorizontal(square)]; - // Same side kings, own king on left - pos.psqtScores[indexColorKingsKingside(pieceSide, 0, 1)] -= PSQTs[0][piece][square]; - // Opposite side kings, own king on right (flip square) - pos.psqtScores[indexColorKingsKingside(pieceSide, 1, 0)] -= PSQTs[1][piece][flipSquareHorizontal(square)]; - // Opposite side kings, own king on left - pos.psqtScores[indexColorKingsKingside(pieceSide, 1, 1)] -= PSQTs[1][piece][square]; -} - -/** - * @brief The addPiece function adds a piece to the board. It also incrementally updates psqt and various hash keys - * @tparam unsafe Set it to true if we are removing a piece that we are sure is not already there - * @param pos the Position object to update - * @param square The square to add the piece to. - * @param piece The piece to add. - */ -template -static inline void addPiece(Position& pos, const Piece piece, const Square square){ - const auto pieceSide = piece >= p; - if constexpr (!unsafe){ - // Remove the piece from the bitboard - setBit(pos.bitboards[piece], square); - // Add it also to the side and both bitboard - setBit(pos.occupancies[piece >= p], square); - setBit(pos.occupancies[BOTH], square); - } - else { - const BitBoard sqb = squareBB(square); - pos.bitboards[piece] ^= sqb; - pos.occupancies[pieceSide] ^= sqb; - pos.occupancies[BOTH] ^= sqb; - } - // Update the hash key - pos.hashKey ^= pieceKeysTable[piece][square]; - pos.pawnHashKey ^= pawnKeysTable[piece][square]; - pos.nonPawnKeys[pieceSide] ^= nonPawnKeysTable[piece][square]; - pos.ptKeys[piece - 6 * (pieceSide)] ^= pieceKeysTable[piece][square]; - // Update the psqt score - // Same side kings, own king on right (flip square) - pos.psqtScores[indexColorKingsKingside(pieceSide, 0, 0)] += PSQTs[0][piece][flipSquareHorizontal(square)]; - // Same side kings, own king on left - pos.psqtScores[indexColorKingsKingside(pieceSide, 0, 1)] += PSQTs[0][piece][square]; - // Opposite side kings, own king on right (flip square) - pos.psqtScores[indexColorKingsKingside(pieceSide, 1, 0)] += PSQTs[1][piece][flipSquareHorizontal(square)]; - // Opposite side kings, own king on left - pos.psqtScores[indexColorKingsKingside(pieceSide, 1, 1)] += PSQTs[1][piece][square]; -} - -bool Position::parseFEN(char *fen) { - - wipe(); - - // The FEN string is split into 6 parts: - // 1. Piece placement - // 2. Active color - // 3. Castling availability - // 4. En passant target square - // 5. Halfmove clock - // 6. Fullmove number - - // We will navigate the string using the pointer fen. - // 1. Piece placement - Square square = a8; - int pieceCount = 0; - fiftyMove = 0; - - while(*fen != ' ') { - if (*fen == '/') { - if (pieceCount != 8) { - std::cout << "Error: Unexpected '/' in FEN string (pieceCount was " << pieceCount << "). Can't parse FEN string" << std::endl; - return false; - } - pieceCount = 0; - fen++; - continue; - } - if (*fen >= '1' && *fen <= '8') { - pieceCount += *fen - '0'; - square += *fen - '0'; - fen++; - continue; - } - if ((*fen >= 'a' && *fen <= 'z') || (*fen >= 'A' && *fen <= 'Z')) { - int piece = charToPiece(*fen); - if (piece == NOPIECE) { - std::cout << "Error: Invalid character in Piece Placement '" << fen[0] << "'. Can't parse FEN string" << std::endl; - return false; - } - addPiece(*this, piece, square); - fen++; - square++; - pieceCount++; - continue; - } - std::cout << "Error: Invalid character in Piece Placement '" << fen[0] << "'. Can't parse FEN string" << std::endl; - return false; - } - - // 2. Active color - fen++; - if (*fen == 'w') { - side = WHITE; - } else if (*fen == 'b') { - side = BLACK; - } else { - std::cout << "Error: Invalid character in Active Color '" << fen[0] << "'. Can't parse FEN string" << std::endl; - return false; - } - - //std::cout << "Turn is now: " << (int)side << std::endl; - - // 3. Castling availability - fen += 2; - castle = 0; - if (*fen != '-') { - while (*fen != ' ') { - if (*fen == 'K') { - castle |= CastleRights::WK; - } else if (*fen == 'Q') { - castle |= CastleRights::WQ; - } else if (*fen == 'k') { - castle |= CastleRights::BK; - } else if (*fen == 'q') { - castle |= CastleRights::BQ; - } else { - std::cout << "Error: Invalid character in Castling Availability '" << fen[0] << "'. Can't parse FEN string" << std::endl; - return false; - } - fen++; - } - } - else { - fen++; - } - - // 4. En passant target square - fen++; - if (*fen == '-') { - enPassant = noSquare; - fen++; - } else { - enPassant = squareFromName(fen); - fen += 2; - if (enPassant == noSquare) { - std::cout << "Error: Invalid character in En Passant Target Square '" << fen[0] << "'. Can't parse FEN string" << std::endl; - return false; - } - } - - // Some fens don't have the halfmove clock and fullmove number, so we need to check for that. - while (*fen == ' ') { - fen++; - } - if (*fen == '\0') { - // If there's no more data, we're done. - goto FENkeyEval; - } - // 5. Halfmove clock - fen++; - fiftyMove = 0; - while (*fen >= '0' && *fen <= '9') { - fiftyMove = fiftyMove * 10 + *fen - '0'; - fen++; - } - - // 6. Fullmove number (not used) - fen++; - totalPly = 0; - while (*fen >= '0' && *fen <= '9') { - totalPly = totalPly * 10 + *fen - '0'; - fen++; - } - - assert(totalPly >= 0); - - // If not given, the fullmove is at least equal to the fifty move counter - if (totalPly == 0) totalPly = fiftyMove; - - if (*fen != '\0') { - // If there's still data left in the string, it's invalid. - // Since the position is already set, we won't return false, but we will print a warning. - //std::cout << "Warning: FEN string contains more data than expected : \""<< fen <<"\". Ignoring it.\n"; - } -FENkeyEval: - // If everything is alright, generate the hash key for the current position - hashKey = generateHashKey(); - pawnHashKey = generatePawnHashKey(); - nonPawnKeys[WHITE] = generateNonPawnHashKey(WHITE); - nonPawnKeys[BLACK] = generateNonPawnHashKey(BLACK); - ptKeys[P] = generatePtHashKey

(); - ptKeys[N] = generatePtHashKey(); - ptKeys[B] = generatePtHashKey(); - ptKeys[R] = generatePtHashKey(); - ptKeys[Q] = generatePtHashKey(); - ptKeys[K] = generatePtHashKey(); - checkers = calculateCheckers(); - generateThreats(); - return true; -} - -void Position::generateThreats() -{ - threats = 0ULL; - const BitBoard occ = occupancies[BOTH]; - - const BitBoard queens = bitboards[q - 6*side]; - BitBoard rooks = bitboards[r - 6*side]; - BitBoard bishops = bitboards[b - 6*side]; - BitBoard knights = bitboards[n - 6*side]; - BitBoard pawns = bitboards[p - 6*side]; - - rooks |= queens; - while (rooks) - { - Square rook = popLsb(rooks); - threats |= getRookAttack(rook, occ); - } - - bishops |= queens; - while (bishops) - { - Square bishop = popLsb(bishops); - threats |= getBishopAttack(bishop, occ); - } - - while (knights) - { - Square knight = popLsb(knights); - threats |= knightAttacks[knight]; - } - - if (side == WHITE) - threats |= makePawnAttacks(pawns); - else - threats |= makePawnAttacks(pawns); - - threats |= kingAttacks[lsb(bitboards[k - 6*side])]; - -} - -/** - * @brief The hasNonPawns function checks if the current side to move has non-pawn material. - * @return true if the position has non-pawn material, false otherwise. - */ -bool Position::hasNonPawns(){ - return occupancies[side] ^ bitboards[P + 6 * side] ^ bitboards[K + 6 * side]; -} - -/** - * @brief The mayBeZugzwang function tries to detect positions where reductions may be unsafe. - * @return True if the position is not to prune, false otherwise. - */ -bool Position::mayBeZugzwang(){ - // We are going to check if there is some non pawn material. - // If there is not, then the position is not to be reduced, since it is simple enough and risky (most zugzwang positions are King and pawn positions) - // We also need to check if there is few material on the board, in which case we make sure there is some legal move for the pawn - // If there is no legal move for the pawn, then the position is possibly a zugzwang - BitBoard nonPawnWhite = bitboards[N] | bitboards[B] | bitboards[R]; - BitBoard nonPawnBlack = bitboards[n] | bitboards[b] | bitboards[r]; - U8 count = (U8)std::max(popcount(nonPawnWhite),popcount(nonPawnBlack)); - if (bitboards[Q] | bitboards[q]) return false; // Queen positions have enough material to not be zugzwang, most of the time - if (count <= 2){ - return true; - } - else if (count <= 5 && (bitboards[P] | bitboards[P])){ - BitBoard freeOccupancy = ~(nonPawnBlack | nonPawnWhite | bitboards[p] | bitboards[P] | bitboards[k] | bitboards[K]); - // To see if there are free squares ahead, we just shift the pawns forward (or backward if white) - if (side == WHITE){ - freeOccupancy &= ~(bitboards[P] >> 8); - } - else{ - freeOccupancy &= ~(bitboards[p] << 8); - } - // If there are no free squares ahead, then the position is likely to be a zugzwang - if (freeOccupancy == 0 ){ - return true; - } - } - return false; -} - -/** - * @brief The isSquareAttacked function returns true if the given square is attacked by the given side. - * @param square The square to check. - * @param side The side to check. - * @return True if the square is attacked, false otherwise. - */ -inline bool Position::isSquareAttacked(U8 square, U8 side){ - if (side == WHITE) { - return (bool)( - (pawnAttacks[BLACK][square] & bitboards[Pieces::P]) || - (knightAttacks[square] & bitboards[Pieces::N]) || - (kingAttacks[square] & bitboards[Pieces::K]) || - (getBishopAttack(square, occupancies[BOTH]) & (bitboards[Pieces::B] | bitboards[Pieces::Q])) || - (getRookAttack(square, occupancies[BOTH]) & (bitboards[Pieces::R] | bitboards[Pieces::Q])) - ); - } - else { - return (bool)( - (pawnAttacks[WHITE][square] & bitboards[Pieces::p]) || - (knightAttacks[square] & bitboards[Pieces::n]) || - (kingAttacks[square] & bitboards[Pieces::k]) || - (getBishopAttack(square, occupancies[BOTH]) & (bitboards[Pieces::b] | bitboards[Pieces::q])) || - (getRookAttack(square, occupancies[BOTH]) & (bitboards[Pieces::r] | bitboards[Pieces::q])) - ); - } -} - -/** - * @brief The attacksToPre function returns a bitboard with all the attackers to a square. - * @param square The square to check. - * @param occupancy an already calculated occupancy - * @param diagonalAttackers an already calculated diagonal attackers - * @param orthogonalAttackers an already calculated orthogonal attackers - * @return A bitboard with all the attackers to the square. - * @TODO: diagonal and orthogonal attackers can be passed as parameters as they are already calculated - */ -inline BitBoard Position::attacksToPre(Square square, BitBoard occupancy, BitBoard diagonalAttackers, BitBoard orthogonalAttackers) { - return ( - (pawnAttacks[WHITE][square] & bitboards[p]) | - (pawnAttacks[BLACK][square] & bitboards[P]) | - (knightAttacks[square] & (bitboards[N] | bitboards[n])) | - (kingAttacks[square] & (bitboards[K] | bitboards[k])) | - (getBishopAttack(square, occupancy) & diagonalAttackers) | - (getRookAttack(square, occupancy) & orthogonalAttackers) - ); - -} - -/** - * @brief The makeMove function makes a move on the board. - * @param move The move to make. - * @return True if the move was made, false otherwise (state of the position is undefined). - */ -bool Position::makeMove(Move move) -{ - - // If the move is invalid, we return false - if (!move) - return false; - - // Get useful information about the move - Square from = moveSource(move); - Square to = moveTarget(move); - Piece piece = movePiece(move); - Piece captured = moveCapture(move); - Piece promotion = movePromotion(move); - bool captures = captured != NOPIECE; - bool promotes = promotion != NOPIECE; - bool doublePawnPush = isDoublePush(move) > 0; - bool isEnPass = isEnPassant(move) > 0; - bool isCastle = isCastling(move) > 0; - - // First, we remove the piece from the source square - removePiece(*this, piece, from); - - // If the move is a capture, we remove the captured piece from the target square - // If the move is a enpassant, we remove the captured pawn from the enPassant square - if (isEnPass){ - removePiece(*this, captured, (side == WHITE ? to + 8 : to - 8)); - addPiece(*this, piece, to); - } - else { - if (captures) - removePiece(*this, captured, to); - - // If the move is a promotion, we replace the piece with the promoted piece - if (promotes) - addPiece(*this, promotion, to); - // Otherwise, we move the piece to the target square - else - addPiece(*this, piece, to); - } - - // Remove the current en passant square from the hash key, as it is no longer valid - hashKey ^= enPassantKeysTable[enPassant]; - pawnHashKey ^= enPassantKeysTable[enPassant]; - enPassant = noSquare; - - - // If the move is a double pawn push, we set the en passant square and hash it back in. If not, we don't need to do anything, since the noSquare hash is 0 - if (doublePawnPush) - enPassant = to + 8 * (1 - 2 * side); - hashKey ^= enPassantKeysTable[enPassant]; - pawnHashKey ^= enPassantKeysTable[enPassant]; - - // If the move is a castle, we move the rook - if (isCastle) - { - switch (to) - { - case g1: - { - // Check if squares between the king and the rook are attacked - if (isSquareAttacked(e1, BLACK) || isSquareAttacked(f1, BLACK) || isSquareAttacked(g1, BLACK)) - return false; - removePiece(*this, R, h1); - addPiece(*this, R, f1); - break; - } - case c1: - { - // Check if squares between the king and the rook are attacked - if (isSquareAttacked(e1, BLACK) || isSquareAttacked(d1, BLACK) || isSquareAttacked(c1, BLACK)) - return false; - removePiece(*this, R, a1); - addPiece(*this, R, d1); - break; - } - case g8: - { - // Check if squares between the king and the rook are attacked - if (isSquareAttacked(e8, WHITE) || isSquareAttacked(f8, WHITE) || isSquareAttacked(g8, WHITE)) - return false; - removePiece(*this, r, h8); - addPiece(*this, r, f8); - break; - } - case c8: - { - // Check if squares between the king and the rook are attacked - if (isSquareAttacked(e8, WHITE) || isSquareAttacked(d8, WHITE) || isSquareAttacked(c8, WHITE)) - return false; - removePiece(*this, r, a8); - addPiece(*this, r, d8); - break; - } - } - } - else{ - // Now we verify if the move is legal. We don't check for legality in the case of a castle, since we already checked for that when we generated the move (castling rights and squares between king and rook are not attacked) - Square ourKing = lsb(bitboards[K + 6 * side]); - if (isSquareAttacked(ourKing, side ^ 1)) - return false; - } - - // Now we update the hash for en passant, castle rights and side to move - hashKey ^= sideKey; - - // Remove previous castle rights - hashKey ^= castleKeysTable[castle]; - - // Add new castle rights - castle &= castlingRights[from]; - castle &= castlingRights[to]; - hashKey ^= castleKeysTable[castle]; - // Change side to move - side ^= 1; - - totalPly++; - plyFromNull++; - - if (isCapture(move) || isPromotion(move) || ((movePiece(move) % 6) == 0)) - fiftyMove = 0; - else - fiftyMove++; - checkers = calculateCheckers(); - generateThreats(); - return true; -} - -inline void Position::addEp(MoveList* ml, ScoredMove move){ - - const S32 score = pieceValues[P] * captScoreMvvMultiplier() - + captureHistoryTable[indexPieceTo(movePiece(move), moveTarget(move))][P][getThreatsIndexing(threats, move)]; - - ml->moves[ml->count++] = (( - score - + GOODNOISYMOVE * SEE(move, -score / (captScoreMvvMultiplier() * 4)) - + BADNOISYMOVE - ) << 32) | move; -} - -template -inline void Position::addPromoCapture(MoveList* ml, ScoredMove move, Piece movedPiece, Piece capturedPiece){ - if constexpr (promotion == R || promotion == B || promotion == r || promotion == b){ - const S32 score = + pieceValues[capturedPiece] * captScoreMvvMultiplier() - + pieceValues[promotion] - + pieceValues[capturedPiece] - - pieceValues[P] - + captureHistoryTable[indexPieceTo(movedPiece, moveTarget(move))][capturedPiece - 6 * (capturedPiece >= 6)][getThreatsIndexing(threats, move)]; // Piece captured can't be NOPIECE (12), so this works - - ml->moves[ml->count++] = (( - score - + BADNOISYMOVE - ) << 32) | move; - } - else { - const S32 score = + pieceValues[capturedPiece] * captScoreMvvMultiplier() - + pieceValues[promotion] - + pieceValues[capturedPiece] - - pieceValues[P] - + captureHistoryTable[indexPieceTo(movedPiece, moveTarget(move))][capturedPiece - 6 * (capturedPiece >= 6)][getThreatsIndexing(threats, move)]; // Piece captured can't be NOPIECE (12), so this works - - ml->moves[ml->count++] = (( - score - + GOODNOISYMOVE * SEE(move, -score / (captScoreMvvMultiplier() * 4)) - + BADNOISYMOVE - ) << 32) | move; - } -} - -inline void Position::addCapture(MoveList* ml, ScoredMove move, Piece movedPiece, Piece capturedPiece){ - - const S32 score = pieceValues[capturedPiece] * captScoreMvvMultiplier() - + captureHistoryTable[indexPieceTo(movedPiece, moveTarget(move))][capturedPiece - 6 * (capturedPiece >= 6)][getThreatsIndexing(threats, move)]; // Piece captured can't be NOPIECE (12), so this works - - ml->moves[ml->count++] = (( - score - + GOODNOISYMOVE * SEE(move, -score / (captScoreMvvMultiplier() * 4)) - + BADNOISYMOVE - ) << 32) | move; - return; -} - -template -inline void Position::addPromotion(MoveList* ml, ScoredMove move){ - if constexpr (promotion == R || promotion == B || promotion == r || promotion == b){ - const S32 score = - + pieceValues[promotion] - - pieceValues[P] - + captureHistoryTable[indexPieceTo(movePiece(move), moveTarget(move))][P][getThreatsIndexing(threats, move)]; - ml->moves[ml->count++] = (( - score - + BADNOISYMOVE - ) << 32) | move; - } - else { - const S32 score = - + pieceValues[promotion] - - pieceValues[P] - + captureHistoryTable[indexPieceTo(movePiece(move), moveTarget(move))][P][getThreatsIndexing(threats, move)]; - - ml->moves[ml->count++] = (( - score - + GOODNOISYMOVE * SEE(move, -score / (captScoreMvvMultiplier() * 4)) - + BADNOISYMOVE - ) << 32) | move; - } - return; -} - -inline void Position::addQuiet(MoveList *ml, ScoredMove move, Square source, Square target, Move killer1, Move killer2, Move counterMove, const S16 *ply1contHist, const S16 *ply2contHist, const S16 *ply4contHist) { - if (sameMovePos(move, killer1)){ - ml->moves[ml->count++] = (KILLER1SCORE << 32) | move; - return; - } - else if (sameMovePos(move, killer2)){ - ml->moves[ml->count++] = (KILLER2SCORE << 32) | move; - return; - } - else if (sameMovePos(move, counterMove)){ - ml->moves[ml->count++] = (COUNTERSCORE << 32) | move; - return; - } - ml->moves[ml->count++] = (( - (S64)(historyTable[side][indexFromTo(source, target)][getThreatsIndexing(threats,move)]) - + (S64)(ply1contHist ? ply1contHist[indexPieceTo(movePiece(move), target)] : 0) - + (S64)(ply2contHist ? ply2contHist[indexPieceTo(movePiece(move), target)] : 0) - + (S64)(ply4contHist ? ply4contHist[indexPieceTo(movePiece(move), target)] : 0) - + QUIETSCORE - ) << 32) | move; -} - -inline void Position::addUnsorted(MoveList* ml, ScoredMove move){ - ml->moves[ml->count++] = move; -} - -bool Position::inCheck() { - Square kingPos = lsb(bitboards[K + 6 * side]); - return isSquareAttacked(kingPos, side ^ 1); -} - -bool Position::insufficientMaterial() { - if (bitboards[P] | bitboards[p] | bitboards[R] | bitboards[r] | bitboards[Q] | bitboards[q]) return false; - BitBoard whiteMinors = bitboards[B] | bitboards[N]; - BitBoard blackMinors = bitboards[b] | bitboards[n]; - switch (popcount(whiteMinors | blackMinors)) { - case 0: case 1: return true; // K vs K + N or K vs K + B - case 2: { - if (whiteMinors && blackMinors) return true; // K + minor vs K + minor is a dead draw - - if (whiteMinors) - return !bitboards[B] || (!bitboards[N] && ((bitboards[B] & squaresOfColor[WHITE]) == bitboards[B])); // KBN or KBB with different color bishops - - return !bitboards[b] || (!bitboards[n] && ((bitboards[b] & squaresOfColor[BLACK]) == bitboards[b])); // Kbn or Kbb with different color bishops - } - default: return false; // 5 pieces are too complex to analyze, we fall back to standard evaluation - } -} - -// Thanks to Weiss chess engine for a clean implementation of this function -bool Position::SEE(const Move move, const Score threshold) { - if (isCastling(move)) return threshold <= 0; // Castling moves don't capture anything, and they don't put the king nor the rook in danger (because of the check rule for castling) - - Square from = moveSource(move); - Square to = moveTarget(move); - - Piece target = moveCapture(move); - Piece promo = movePromotion(move); - Score value = pieceValues[target] - threshold; - - // If the move is a promotion, we need to consider the value of the promoted piece (and remove the value of the pawn) - if (promo != NOPIECE) value += pieceValues[promo] - pieceValues[P]; - - // Check for early SEE exit (if the threshold is still negative) - if (value < 0) return false; - - Piece attacker = movePiece(move); - - // Check for another early SEE exit (if immediate recapture still beats the threshold) - value -= promo != NOPIECE ? pieceValues[promo] : pieceValues[attacker]; - if (value >= 0) return true; - - // Initialize the attackers, occupancies, vertical and horizontal sliders - BitBoard occupied = occupancies[BOTH] ^ squareBB(from); - if (isEnPassant(move)) occupied ^= squareBB(to + (side == WHITE ? 8 : -8)); - - BitBoard diagonalSliders = bitboards[Q] | bitboards[q] | bitboards[B] | bitboards[b]; - BitBoard orthogonalSliders = bitboards[Q] | bitboards[q] | bitboards[R] | bitboards[r]; - - BitBoard attackers = attacksToPre(to, occupied, diagonalSliders, orthogonalSliders); - - const U8 us = attacker < 6 ? WHITE : BLACK; // Side of the attacker - - U8 side = us ^ 1; // Side of the attacker, flipped (one move already executed) - - while (true){ - attackers &= occupied; - BitBoard ourAttackers = attackers & occupancies[side]; - if (!ourAttackers) break; // We run out of attackers - - // Find the least valuable attacker - Piece pt; - for (pt = P; pt < K; ++pt) - if (ourAttackers & bitboards[pt + 6 * side]) break; - - side ^= 1; - - // Update the value - value = -value -1 - pieceValues[pt]; - - // Check if value beats threshold - if (value >= 0) { - // Special case for king captures, as we need to check if the king is in check after the capture - if (pt == K && (attackers & occupancies[side])) side ^= 1; // So that if our kings ends up in check we fail, if their king ends up in check we succeed - break; - } - - // Remove the used piece from the board - clearBit(occupied, lsb(ourAttackers & (bitboards[pt] | bitboards[pt + 6]))); - - // Update the attackers - if (pt == P || pt == B || pt == Q) attackers |= getBishopAttack(to, occupied) & diagonalSliders; - if (pt == R || pt == Q) attackers |= getRookAttack(to, occupied) & orthogonalSliders; - } - - // Check who runs out of attackers - return side != us; -} - - -void Position::reflect() { - // reflect psqt - std::swap(psqtScores[indexColorKingsKingside(WHITE,0,0)], psqtScores[indexColorKingsKingside(BLACK,0,0)]); - std::swap(psqtScores[indexColorKingsKingside(WHITE,0,1)], psqtScores[indexColorKingsKingside(BLACK,0,1)]); - std::swap(psqtScores[indexColorKingsKingside(WHITE,1,0)], psqtScores[indexColorKingsKingside(BLACK,1,0)]); - std::swap(psqtScores[indexColorKingsKingside(WHITE,1,1)], psqtScores[indexColorKingsKingside(BLACK,1,1)]); - // First, swap white with black - for (int i = P; i <= K; i++) { - bitboards[i] ^= bitboards[i + 6]; - bitboards[i+6] ^= bitboards[i]; - bitboards[i] ^= bitboards[i + 6]; - } - // First, we will reflect the bitboards - for (int i = 0; i < 12; i++) { - bitboards[i] = reflectBitBoard(bitboards[i]); - } - occupancies[WHITE] = bitboards[P] | bitboards[N] | bitboards[B] | bitboards[R] | bitboards[Q] | bitboards[K]; - occupancies[BLACK] = bitboards[p] | bitboards[n] | bitboards[b] | bitboards[r] | bitboards[q] | bitboards[k]; - occupancies[BOTH] = occupancies[WHITE] | occupancies[BLACK]; - // Then reflect ep square - enPassant = enPassant == noSquare ? noSquare : flipSquare(enPassant); - // Then reflect the castling rights - U8 newCastle = 0; - newCastle |= WK * (!!(castle & BK)); - newCastle |= WQ * (!!(castle & BQ)); - newCastle |= BK * (!!(castle & WK)); - newCastle |= BQ * (!!(castle & WQ)); - - castle = newCastle; - // Then reflect the side to move - side = side == WHITE ? BLACK : WHITE; - // Recalculate hash - hashKey = generateHashKey(); - pawnHashKey = generatePawnHashKey(); - nonPawnKeys[WHITE] = generateNonPawnHashKey(WHITE); - nonPawnKeys[BLACK] = generateNonPawnHashKey(BLACK); - ptKeys[P] = generatePtHashKey

(); - ptKeys[N] = generatePtHashKey(); - ptKeys[B] = generatePtHashKey(); - ptKeys[R] = generatePtHashKey(); - ptKeys[Q] = generatePtHashKey(); - ptKeys[K] = generatePtHashKey(); - generateThreats(); -} - -std::string Position::getFEN() { - std::string fen = ""; - int empty = 0; - for (Square square = a8; square < noSquare; ++square) { - Piece p = pieceOn(square); - if ( p == NOPIECE) empty++; - else { - if (empty) fen.append(1, ('0' + empty)); - empty = 0; - fen.append(1, getPieceChar(p)); - } - if ((square % 8 == 7) && (square != h1)) { - if (empty) fen.append(1, ('0' + empty)); - empty = 0; - fen += "/"; - } - } - - fen += " "; - fen += side ? "b " : "w "; - if (castle) { - if (castle & CastleRights::WK) fen += "K"; - if (castle & CastleRights::WQ) fen += "Q"; - if (castle & CastleRights::BK) fen += "k"; - if (castle & CastleRights::BQ) fen += "q"; - fen += " "; - } - else { - fen += "- "; - } - - if (enPassant != noSquare) { - fen += coords[enPassant] + " "; - } - else { - fen += "- "; - } - return fen; -} - -/** - * @brief The generateMoves function generates all pseudo legal moves for the current side. - * @param moveList The moveList to fill with the generated moves. - * @param ss The search stack, to get the killers and counter moves. - */ -void Position::generateMoves(MoveList& moveList, SStack* ss) { - - const Move killer1 = ss->killers[0]; - const Move killer2 = ss->killers[1]; - const Move lastMove = (ss-1)->move; - const Move counterMove = lastMove ? counterMoveTable[indexFromTo(moveSource(lastMove), moveTarget(lastMove))] : noMove; - const S16 *ply1contHist = lastMove ? (ss - 1)->contHistEntry : nullptr; - const S16 *ply2contHist = (ss - 2)->move ? (ss - 2)->contHistEntry : nullptr; - const S16 *ply4contHist = (ss - 4)->move ? (ss - 4)->contHistEntry : nullptr; - - BitBoard ourPawns = bitboards[P + 6 * side]; - BitBoard ourKnights = bitboards[N + 6 * side]; - BitBoard ourBishops = bitboards[B + 6 * side]; - BitBoard ourRooks = bitboards[R + 6 * side]; - BitBoard ourQueens = bitboards[Q + 6 * side]; - BitBoard ourKing = bitboards[K + 6 * side]; - - BitBoard theirKing = bitboards[K + 6 * (side ^ 1)]; - - BitBoard theirPieces = occupancies[side ^ 1]; - BitBoard occupancy = occupancies[BOTH]; - - - Square theirKingPos = lsb(theirKing); - - BitBoard pawnCheckers = pawnAttacks[side ^ 1][theirKingPos]; - BitBoard knightCheckers = knightAttacks[theirKingPos]; - BitBoard bishopCheckers = getBishopAttack(theirKingPos, occupancy); - BitBoard rookCheckers = getRookAttack(theirKingPos, occupancy); - BitBoard queenCheckers = bishopCheckers | rookCheckers; - - // We will generate the moves in a way that the sort function will need to do minimal work - // We will generate first moves that we expect to have an higher probability of being useful (high score moves) - // The order will be as follows: - - // 1. Pawn captures, Knight captures - // 2. Sliders captures - // 3. King captures, castling moves - // 4. Pawn moves - // 5. Sliders moves - // 6. Knight moves - // 7. King moves - - // The score of a move is the sum of the following values: - // 1. The value given by the mvvlva table (for captures) and a bonus for promotions - // 2. The value given by the killer table (for non captures) - // 3. The value given by the history table (for non captures) - // 4. The value given by the counter move table (for non captures) - // 5. The value given by the follow up move table (for non captures) - // 6. A bonus for moves that give check (for non captures) - // 7. A bonus for castling moves and double pawn pushes - - // We will generate moves for the pawns first - if (side == WHITE) { - // We generate the pawn captures. Pawn captures are generated by shifting by 7 or 9 squares - BitBoard nonAPawns = ourPawns & ~files(0); - BitBoard nonHPawns = ourPawns & ~files(7); - BitBoard dxPawnCaptures = nonHPawns >> 7; - BitBoard sxPawnCaptures = nonAPawns >> 9; - dxPawnCaptures &= theirPieces; - sxPawnCaptures &= theirPieces; - // Right captures - while (dxPawnCaptures) { - Square to = popLsb(dxPawnCaptures); - Piece captured = pieceOn(to); - if (to <= h8) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, Q, false, false, false, (queenCheckers & squareBB(to)) > 0) , P, captured); - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, R, false, false, false, (rookCheckers & squareBB(to)) > 0) , P, captured); - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, B, false, false, false, (bishopCheckers & squareBB(to)) > 0) , P, captured); - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, N, false, false, false, (knightCheckers & squareBB(to)) > 0) , P, captured); - } - else - addCapture(&moveList, encodeMove(to + 7, to, P, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), P, captured); - } - // Left captures - while (sxPawnCaptures) { - Square to = popLsb(sxPawnCaptures); - Piece captured = pieceOn(to); - if (to <= h8) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, Q, false, false, false, (queenCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, R, false, false, false, (rookCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, B, false, false, false, (bishopCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, N, false, false, false, (knightCheckers & squareBB(to)) > 0), P, captured); - } - else - addCapture(&moveList, encodeMove(to + 9, to, P, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), P, captured); - } - // En passant capture (if there is one) - if (enPassant != noSquare) { - Square to = enPassant; - BitBoard epPawns = pawnAttacks[side ^ 1][to] & ourPawns; - while (epPawns) { - Square from = popLsb(epPawns); - addEp(&moveList, encodeMove(from, to, P, p, NOPIECE, false, true, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - } - else { - // We generate the pawn captures. Pawn captures are generated by shifting by 7 or 9 squares - BitBoard nonAPawns = ourPawns & ~files(0); - BitBoard nonHPawns = ourPawns & ~files(7); - BitBoard dxPawnCaptures = nonHPawns << 9; - BitBoard sxPawnCaptures = nonAPawns << 7; - dxPawnCaptures &= theirPieces; - sxPawnCaptures &= theirPieces; - // Right captures - while (dxPawnCaptures) { - Square to = popLsb(dxPawnCaptures); - Piece captured = pieceOn(to); - if (to >= a1) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, q, false, false, false, (queenCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, r, false, false, false, (rookCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, b, false, false, false, (bishopCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, n, false, false, false, (knightCheckers & squareBB(to)) > 0), p, captured); - } - else - addCapture(&moveList, encodeMove(to - 9, to, p, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), p, captured); - } - // Left captures - while (sxPawnCaptures) { - Square to = popLsb(sxPawnCaptures); - Piece captured = pieceOn(to); - if (to >= a1) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, q, false, false, false, (queenCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, r, false, false, false, (rookCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, b, false, false, false, (bishopCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, n, false, false, false, (knightCheckers & squareBB(to)) > 0), p, captured); - } - else - addCapture(&moveList, encodeMove(to - 7, to, p, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), p, captured); - } - // En passant capture (if there is one) - if (enPassant != noSquare) { - Square to = enPassant; - BitBoard epPawns = pawnAttacks[side ^ 1][to] & ourPawns; - while (epPawns) { - Square from = popLsb(epPawns); - addEp(&moveList, encodeMove(from, to, p, P, NOPIECE, false, true, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - } - // We will generate the knight moves - BitBoard knights = ourKnights; - while (knights) { - Square from = popLsb(knights); - BitBoard attacks = knightAttacks[from]; - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (knightCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, N + 6 * side, captured, NOPIECE, false, false, false, isCheck), N + 6 * side, captured); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (knightCheckers & squareBB(to)) > 0; - addQuiet(&moveList, encodeMove(from, to, N + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck), from, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - // We will generate the bishop moves - BitBoard bishops = ourBishops; - while (bishops) { - Square from = popLsb(bishops); - BitBoard attacks = getBishopAttack(from, occupancy); - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (bishopCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, B + 6 * side, captured, NOPIECE, false, false, false, isCheck), B + 6 * side, captured); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (bishopCheckers & squareBB(to)) > 0; - addQuiet(&moveList, encodeMove(from, to, B + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck), from, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - // We will generate the rook moves - BitBoard rooks = ourRooks; - while (rooks) { - Square from = popLsb(rooks); - BitBoard attacks = getRookAttack(from, occupancy); - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (rookCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, R + 6 * side, captured, NOPIECE, false, false, false, isCheck), R + 6 * side, captured); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (rookCheckers & squareBB(to)) > 0; - addQuiet(&moveList, encodeMove(from, to, R + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck), from, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - // We will generate the queen moves - BitBoard queens = ourQueens; - while (queens) { - Square from = popLsb(queens); - BitBoard attacks = getQueenAttack(from, occupancy); - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (queenCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, Q + 6 * side, captured, NOPIECE, false, false, false, isCheck), Q + 6 * side, captured); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (queenCheckers & squareBB(to)) > 0; - addQuiet(&moveList, encodeMove(from, to, Q + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck), from, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - // We will generate the pawn pushes - if (side == WHITE) { - BitBoard pawnPushes = ourPawns >> 8; - pawnPushes &= ~occupancy; - - while (pawnPushes) { - Square to = popLsb(pawnPushes); - if (to <= h8) { - // We will generate the promotion moves - addPromotion(&moveList, encodeMove(to + 8, to, P, NOPIECE, Q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addPromotion(&moveList, encodeMove(to + 8, to, P, NOPIECE, R, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addPromotion(&moveList, encodeMove(to + 8, to, P, NOPIECE, B, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addPromotion(&moveList, encodeMove(to + 8, to, P, NOPIECE, N, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addQuiet(&moveList, encodeMove(to + 8, to, P, NOPIECE, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), to + 8, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - - BitBoard pawnDoublePushes = ourPawns & ranks(6); - pawnDoublePushes >>= 8; - pawnDoublePushes &= ~occupancy; - pawnDoublePushes >>= 8; - pawnDoublePushes &= ~occupancy; - while (pawnDoublePushes) { - Square to = popLsb(pawnDoublePushes); - addQuiet(&moveList, encodeMove(to + 16, to, P, NOPIECE, NOPIECE, true, false, false, (pawnCheckers & squareBB(to)) > 0), to + 16, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - else { - BitBoard pawnPushes = ourPawns << 8; - pawnPushes &= ~occupancy; - while (pawnPushes) { - Square to = popLsb(pawnPushes); - if (to >= a1) { - // We will generate the promotion moves - addPromotion(&moveList, encodeMove(to - 8, to, p, NOPIECE, q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addPromotion(&moveList, encodeMove(to - 8, to, p, NOPIECE, r, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addPromotion(&moveList, encodeMove(to - 8, to, p, NOPIECE, b, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addPromotion(&moveList, encodeMove(to - 8, to, p, NOPIECE, n, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addQuiet(&moveList, encodeMove(to - 8, to, p, NOPIECE, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), to - 8, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - BitBoard pawnDoublePushes = ourPawns & ranks(1); - pawnDoublePushes <<= 8; - pawnDoublePushes &= ~occupancy; - pawnDoublePushes <<= 8; - pawnDoublePushes &= ~occupancy; - while (pawnDoublePushes) { - Square to = popLsb(pawnDoublePushes); - addQuiet(&moveList, encodeMove(to - 16, to, p, NOPIECE, NOPIECE, true, false, false, (pawnCheckers & squareBB(to)) > 0), to - 16, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - // We will generate the king moves, including castling - Square king = lsb(ourKing); - BitBoard kAttacks = kingAttacks[king]; - BitBoard kMoves = kAttacks & ~occupancy; - kAttacks &= theirPieces; - while (kAttacks) { - Square to = popLsb(kAttacks); - Piece captured = pieceOn(to); - addCapture(&moveList, encodeMove(king, to, K + 6 * side, captured, NOPIECE, false, false, false, false), K + 6 * side, captured); - } - while (kMoves) { - Square to = popLsb(kMoves); - addQuiet(&moveList, encodeMove(king, to, K + 6 * side, NOPIECE, NOPIECE, false, false, false, false), king, to, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - // We will generate the castling moves - if (side == WHITE) { - if (castle & CastleRights::WK && !(occupancy & wKCastleMask)) { - addQuiet(&moveList, encodeMove(e1, g1, K, NOPIECE, NOPIECE, false, false, true, false), e1, g1, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - if (castle & CastleRights::WQ && !(occupancy & wQCastleMask)) { - addQuiet(&moveList, encodeMove(e1, c1, K, NOPIECE, NOPIECE, false, false, true, false), e1, c1, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } - else { - if (castle & CastleRights::BK && !(occupancy & bKCastleMask)) { - addQuiet(&moveList, encodeMove(e8, g8, k, NOPIECE, NOPIECE, false, false, true, false), e8, g8, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - if (castle & CastleRights::BQ && !(occupancy & bQCastleMask)) { - addQuiet(&moveList, encodeMove(e8, c8, k, NOPIECE, NOPIECE, false, false, true, false), e8, c8, killer1, killer2, counterMove, ply1contHist, ply2contHist, ply4contHist); - } - } -} - -void Position::generateCaptures(MoveList &moveList){ - moveList.clear(); - BitBoard ourPawns = bitboards[P + 6 * side]; - BitBoard ourKnights = bitboards[N + 6 * side]; - BitBoard ourBishops = bitboards[B + 6 * side]; - BitBoard ourRooks = bitboards[R + 6 * side]; - BitBoard ourQueens = bitboards[Q + 6 * side]; - BitBoard ourKing = bitboards[K + 6 * side]; - - BitBoard theirKing = bitboards[K + 6 * (side ^ 1)]; - - BitBoard theirPieces = occupancies[side ^ 1]; - BitBoard occupancy = occupancies[BOTH]; - - Square theirKingPos = lsb(theirKing); - - BitBoard pawnCheckers = pawnAttacks[side^1][theirKingPos]; - BitBoard knightCheckers = knightAttacks[theirKingPos]; - BitBoard bishopCheckers = getBishopAttack(theirKingPos, occupancy); - BitBoard rookCheckers = getRookAttack(theirKingPos, occupancy); - BitBoard queenCheckers = getQueenAttack(theirKingPos, occupancy); - - // We will generate the moves in a way that the sort function will need to do minimal work - // We will generate first moves that we expect to have an higher probability of being useful (high score moves) - // The order will be as follows: - - // 1. Pawn captures, Knight captures - // 2. Sliders captures - // 3. King captures, castling moves - // 4. Pawn moves - // 5. Sliders moves - // 6. Knight moves - // 7. King moves - - // The score of a move is the sum of the following values: - // 1. The value given by the mvvlva table (for captures) and a bonus for promotions - // 2. The value given by the killer table (for non captures) - // 3. The value given by the history table (for non captures) - // 4. The value given by the counter move table (for non captures) - // 5. The value given by the follow up move table (for non captures) - // 6. A bonus for moves that give check (for non captures) - // 7. A bonus for castling moves and double pawn pushes - - // We will generate moves for the pawns first - if (side == WHITE){ - // We generate the pawn captures. Pawn captures are generated by shifting by 7 or 9 squares - BitBoard nonAPawns = ourPawns & ~files(0); - BitBoard nonHPawns = ourPawns & ~files(7); - BitBoard dxPawnCaptures = nonHPawns >> 7; - BitBoard sxPawnCaptures = nonAPawns >> 9; - dxPawnCaptures &= theirPieces; - sxPawnCaptures &= theirPieces; - // Right captures - while (dxPawnCaptures){ - Square to = popLsb(dxPawnCaptures); - Piece captured = pieceOn(to); - if (to <= h8) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, Q, false, false, false, (queenCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, R, false, false, false, (rookCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, B, false, false, false, (bishopCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 7, to, P, captured, N, false, false, false, (knightCheckers & squareBB(to)) > 0), P, captured); - } - else - addCapture(&moveList, encodeMove(to + 7, to, P, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), P, captured); - } - // Left captures - while (sxPawnCaptures){ - Square to = popLsb(sxPawnCaptures); - Piece captured = pieceOn(to); - if (to <= h8) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, Q, false, false, false, (queenCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, R, false, false, false, (rookCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, B, false, false, false, (bishopCheckers & squareBB(to)) > 0), P, captured); - addPromoCapture(&moveList, encodeMove(to + 9, to, P, captured, N, false, false, false, (knightCheckers & squareBB(to)) > 0), P, captured); - } - else - addCapture(&moveList, encodeMove(to + 9, to, P, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), P, captured); - } - // En passant capture (if there is one) - if (enPassant != noSquare){ - Square to = enPassant; - BitBoard epPawns = pawnAttacks[side^1][to] & ourPawns; - while (epPawns){ - Square from = popLsb(epPawns); - addEp(&moveList, encodeMove(from, to, P, p, NOPIECE, false, true, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - } - else { - // We generate the pawn captures. Pawn captures are generated by shifting by 7 or 9 squares - BitBoard nonAPawns = ourPawns & ~files(0); - BitBoard nonHPawns = ourPawns & ~files(7); - BitBoard dxPawnCaptures = nonHPawns << 9; - BitBoard sxPawnCaptures = nonAPawns << 7; - dxPawnCaptures &= theirPieces; - sxPawnCaptures &= theirPieces; - // Right captures - while (dxPawnCaptures){ - Square to = popLsb(dxPawnCaptures); - Piece captured = pieceOn(to); - if (to >= a1) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, q, false, false, false, (queenCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, r, false, false, false, (rookCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, b, false, false, false, (bishopCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 9, to, p, captured, n, false, false, false, (knightCheckers & squareBB(to)) > 0), p, captured); - } - else - addCapture(&moveList, encodeMove(to - 9, to, p, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), p, captured); - } - // Left captures - while (sxPawnCaptures){ - Square to = popLsb(sxPawnCaptures); - Piece captured = pieceOn(to); - if (to >= a1) { - // We have a promotion - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, q, false, false, false, (queenCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, r, false, false, false, (rookCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, b, false, false, false, (bishopCheckers & squareBB(to)) > 0), p, captured); - addPromoCapture(&moveList, encodeMove(to - 7, to, p, captured, n, false, false, false, (knightCheckers & squareBB(to)) > 0), p, captured); - } - else - addCapture(&moveList, encodeMove(to - 7, to, p, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0), p, captured); - } - // En passant capture (if there is one) - if (enPassant != noSquare){ - Square to = enPassant; - BitBoard epPawns = pawnAttacks[side^1][to] & ourPawns; - while (epPawns){ - Square from = popLsb(epPawns); - addEp(&moveList, encodeMove(from, to, p, P, NOPIECE, false, true, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - } - // We will generate the knight moves - BitBoard knights = ourKnights; - while(knights){ - Square from = popLsb(knights); - BitBoard attacks = knightAttacks[from]; - attacks &= theirPieces; - while(attacks){ - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (knightCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, N + 6 * side, captured, NOPIECE, false, false, false, isCheck), N + 6 * side, captured); - } - } - // We will generate the bishop moves - BitBoard bishops = ourBishops; - while (bishops){ - Square from = popLsb(bishops); - BitBoard attacks = getBishopAttack(from, occupancy); - attacks &= theirPieces; - while(attacks){ - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (bishopCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, B + 6 * side, captured, NOPIECE, false, false, false, isCheck), B + 6 * side, captured); - } - } - // We will generate the rook moves - BitBoard rooks = ourRooks; - while (rooks){ - Square from = popLsb(rooks); - BitBoard attacks = getRookAttack(from, occupancy); - attacks &= theirPieces; - while(attacks){ - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (rookCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, R + 6 * side, captured, NOPIECE, false, false, false, isCheck), R + 6 * side, captured); - } - } - // We will generate the queen moves - BitBoard queens = ourQueens; - while (queens){ - Square from = popLsb(queens); - BitBoard attacks = getQueenAttack(from, occupancy); - attacks &= theirPieces; - while(attacks){ - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (queenCheckers & squareBB(to)) > 0; - addCapture(&moveList, encodeMove(from, to, Q + 6 * side, captured, NOPIECE, false, false, false, isCheck), Q + 6 * side, captured); - } - } - // We will generate the king moves, including castling - Square king = lsb(ourKing); - BitBoard kAttacks = kingAttacks[king]; - kAttacks &= theirPieces; - while(kAttacks){ - Square to = popLsb(kAttacks); - Piece captured = pieceOn(to); - addCapture(&moveList, encodeMove(king, to, K + 6 * side, captured, NOPIECE, false, false, false, false), K + 6 * side, captured); - } -} - -/** - * @brief The generateUnsortedMoves function generates all pseudo legal moves for the current side. Used for perft testing (when we don't care about the move ordering). - * @param moveList The moveList to fill with the generated moves. - */ -void Position::generateUnsortedMoves(MoveList& moveList) { - - BitBoard ourPawns = bitboards[P + 6 * side]; - BitBoard ourKnights = bitboards[N + 6 * side]; - BitBoard ourBishops = bitboards[B + 6 * side]; - BitBoard ourRooks = bitboards[R + 6 * side]; - BitBoard ourQueens = bitboards[Q + 6 * side]; - BitBoard ourKing = bitboards[K + 6 * side]; - - BitBoard theirKing = bitboards[K + 6 * (side ^ 1)]; - - BitBoard theirPieces = occupancies[side ^ 1]; - BitBoard occupancy = occupancies[BOTH]; - - - Square theirKingPos = lsb(theirKing); - - BitBoard pawnCheckers = pawnAttacks[side ^ 1][theirKingPos]; - BitBoard knightCheckers = knightAttacks[theirKingPos]; - BitBoard bishopCheckers = getBishopAttack(theirKingPos, occupancy); - BitBoard rookCheckers = getRookAttack(theirKingPos, occupancy); - BitBoard queenCheckers = bishopCheckers | rookCheckers; - - // We will generate moves for the pawns first - if (side == WHITE) { - // We generate the pawn captures. Pawn captures are generated by shifting by 7 or 9 squares - BitBoard nonAPawns = ourPawns & ~files(0); - BitBoard nonHPawns = ourPawns & ~files(7); - BitBoard dxPawnCaptures = nonHPawns >> 7; - BitBoard sxPawnCaptures = nonAPawns >> 9; - dxPawnCaptures &= theirPieces; - sxPawnCaptures &= theirPieces; - // Right captures - while (dxPawnCaptures) { - Square to = popLsb(dxPawnCaptures); - Piece captured = pieceOn(to); - if (to <= h8) { - // We have a promotion - addUnsorted(&moveList, encodeMove(to + 7, to, P, captured, Q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 7, to, P, captured, R, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 7, to, P, captured, B, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 7, to, P, captured, N, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addUnsorted(&moveList, encodeMove(to + 7, to, P, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - // Left captures - while (sxPawnCaptures) { - Square to = popLsb(sxPawnCaptures); - Piece captured = pieceOn(to); - if (to <= h8) { - // We have a promotion - addUnsorted(&moveList, encodeMove(to + 9, to, P, captured, Q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 9, to, P, captured, R, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 9, to, P, captured, B, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 9, to, P, captured, N, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addUnsorted(&moveList, encodeMove(to + 9, to, P, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - // En passant capture (if there is one) - if (enPassant != noSquare) { - Square to = enPassant; - BitBoard epPawns = pawnAttacks[side ^ 1][to] & ourPawns; - while (epPawns) { - Square from = popLsb(epPawns); - addUnsorted(&moveList, encodeMove(from, to, P, p, NOPIECE, false, true, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - } - else { - // We generate the pawn captures. Pawn captures are generated by shifting by 7 or 9 squares - BitBoard nonAPawns = ourPawns & ~files(0); - BitBoard nonHPawns = ourPawns & ~files(7); - BitBoard dxPawnCaptures = nonHPawns << 9; - BitBoard sxPawnCaptures = nonAPawns << 7; - dxPawnCaptures &= theirPieces; - sxPawnCaptures &= theirPieces; - // Right captures - while (dxPawnCaptures) { - Square to = popLsb(dxPawnCaptures); - Piece captured = pieceOn(to); - if (to >= a1) { - // We have a promotion - addUnsorted(&moveList, encodeMove(to - 9, to, p, captured, q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 9, to, p, captured, r, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 9, to, p, captured, b, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 9, to, p, captured, n, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addUnsorted(&moveList, encodeMove(to - 9, to, p, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - // Left captures - while (sxPawnCaptures) { - Square to = popLsb(sxPawnCaptures); - Piece captured = pieceOn(to); - if (to >= a1) { - // We have a promotion - addUnsorted(&moveList, encodeMove(to - 7, to, p, captured, q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 7, to, p, captured, r, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 7, to, p, captured, b, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 7, to, p, captured, n, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addUnsorted(&moveList, encodeMove(to - 7, to, p, captured, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - // En passant capture (if there is one) - if (enPassant != noSquare) { - Square to = enPassant; - BitBoard epPawns = pawnAttacks[side ^ 1][to] & ourPawns; - while (epPawns) { - Square from = popLsb(epPawns); - addUnsorted(&moveList, encodeMove(from, to, p, P, NOPIECE, false, true, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - } - // We will generate the knight moves - BitBoard knights = ourKnights; - while (knights) { - Square from = popLsb(knights); - BitBoard attacks = knightAttacks[from]; - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (knightCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, N + 6 * side, captured, NOPIECE, false, false, false, isCheck)); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (knightCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, N + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck)); - } - } - // We will generate the bishop moves - BitBoard bishops = ourBishops; - while (bishops) { - Square from = popLsb(bishops); - BitBoard attacks = getBishopAttack(from, occupancy); - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (bishopCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, B + 6 * side, captured, NOPIECE, false, false, false, isCheck)); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (bishopCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, B + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck)); - } - } - // We will generate the rook moves - BitBoard rooks = ourRooks; - while (rooks) { - Square from = popLsb(rooks); - BitBoard attacks = getRookAttack(from, occupancy); - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (rookCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, R + 6 * side, captured, NOPIECE, false, false, false, isCheck)); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (rookCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, R + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck)); - } - } - // We will generate the queen moves - BitBoard queens = ourQueens; - while (queens) { - Square from = popLsb(queens); - BitBoard attacks = getQueenAttack(from, occupancy); - BitBoard quiets = attacks & ~occupancy; - attacks &= theirPieces; - while (attacks) { - Square to = popLsb(attacks); - Piece captured = pieceOn(to); - bool isCheck = (queenCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, Q + 6 * side, captured, NOPIECE, false, false, false, isCheck)); - } - while (quiets) { - Square to = popLsb(quiets); - bool isCheck = (queenCheckers & squareBB(to)) > 0; - addUnsorted(&moveList, encodeMove(from, to, Q + 6 * side, NOPIECE, NOPIECE, false, false, false, isCheck)); - } - } - // We will generate the pawn pushes - if (side == WHITE) { - BitBoard pawnPushes = ourPawns >> 8; - pawnPushes &= ~occupancy; - - while (pawnPushes) { - Square to = popLsb(pawnPushes); - if (to <= h8) { - // We will generate the promotion moves - addUnsorted(&moveList, encodeMove(to + 8, to, P, NOPIECE, Q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 8, to, P, NOPIECE, R, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 8, to, P, NOPIECE, B, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to + 8, to, P, NOPIECE, N, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addUnsorted(&moveList, encodeMove(to + 8, to, P, NOPIECE, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - - BitBoard pawnDoublePushes = ourPawns & ranks(6); - pawnDoublePushes >>= 8; - pawnDoublePushes &= ~occupancy; - pawnDoublePushes >>= 8; - pawnDoublePushes &= ~occupancy; - while (pawnDoublePushes) { - Square to = popLsb(pawnDoublePushes); - addUnsorted(&moveList, encodeMove(to + 16, to, P, NOPIECE, NOPIECE, true, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - else { - BitBoard pawnPushes = ourPawns << 8; - pawnPushes &= ~occupancy; - while (pawnPushes) { - Square to = popLsb(pawnPushes); - if (to >= a1) { - // We will generate the promotion moves - addUnsorted(&moveList, encodeMove(to - 8, to, p, NOPIECE, q, false, false, false, (queenCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 8, to, p, NOPIECE, r, false, false, false, (rookCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 8, to, p, NOPIECE, b, false, false, false, (bishopCheckers & squareBB(to)) > 0)); - addUnsorted(&moveList, encodeMove(to - 8, to, p, NOPIECE, n, false, false, false, (knightCheckers & squareBB(to)) > 0)); - } - else - addUnsorted(&moveList, encodeMove(to - 8, to, p, NOPIECE, NOPIECE, false, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - BitBoard pawnDoublePushes = ourPawns & ranks(1); - pawnDoublePushes <<= 8; - pawnDoublePushes &= ~occupancy; - pawnDoublePushes <<= 8; - pawnDoublePushes &= ~occupancy; - while (pawnDoublePushes) { - Square to = popLsb(pawnDoublePushes); - addUnsorted(&moveList, encodeMove(to - 16, to, p, NOPIECE, NOPIECE, true, false, false, (pawnCheckers & squareBB(to)) > 0)); - } - } - // We will generate the king moves, including castling - Square king = lsb(ourKing); - BitBoard kAttacks = kingAttacks[king]; - BitBoard kMoves = kAttacks & ~occupancy; - kAttacks &= theirPieces; - while (kAttacks) { - Square to = popLsb(kAttacks); - Piece captured = pieceOn(to); - addUnsorted(&moveList, encodeMove(king, to, K + 6 * side, captured, NOPIECE, false, false, false, false)); - } - while (kMoves) { - Square to = popLsb(kMoves); - addUnsorted(&moveList, encodeMove(king, to, K + 6 * side, NOPIECE, NOPIECE, false, false, false, false)); - } - // We will generate the castling moves - if (side == WHITE) { - if (castle & CastleRights::WK && !(occupancy & wKCastleMask)) { - addUnsorted(&moveList, encodeMove(e1, g1, K, NOPIECE, NOPIECE, false, false, true, false)); - } - if (castle & CastleRights::WQ && !(occupancy & wQCastleMask)) { - addUnsorted(&moveList, encodeMove(e1, c1, K, NOPIECE, NOPIECE, false, false, true, false)); - } - } - else { - if (castle & CastleRights::BK && !(occupancy & bKCastleMask)) { - addUnsorted(&moveList, encodeMove(e8, g8, k, NOPIECE, NOPIECE, false, false, true, false)); - } - if (castle & CastleRights::BQ && !(occupancy & bQCastleMask)) { - addUnsorted(&moveList, encodeMove(e8, c8, k, NOPIECE, NOPIECE, false, false, true, false)); - } - } -} - -/** - * @brief The makeNullMove function makes a null move on the board. - */ -void Position::makeNullMove(){ - side ^= 1; - hashKey ^= sideKey; - hashKey ^= enPassantKeysTable[enPassant]; - pawnHashKey ^= enPassantKeysTable[enPassant]; - enPassant = noSquare; - fiftyMove++; - totalPly++; - plyFromNull = 0; - checkers = 0ULL; // null moves will never be done while in check. - generateThreats(); -} - -UndoInfo::UndoInfo(Position& position){ - hashKey = position.hashKey; - pawnsHashKey = position.pawnHashKey; - nonPawnsHashKey[WHITE] = position.nonPawnKeys[WHITE]; - nonPawnsHashKey[BLACK] = position.nonPawnKeys[BLACK]; - enPassant = position.enPassant; - castle = position.castle; - fiftyMove = position.fiftyMove; - totalPly = position.totalPly; - plyFromNull = position.plyFromNull; - side = position.side; - checkers = position.checkers; - threats = position.threats; - memcpy(psqtScores, position.psqtScores, sizeof(psqtScores)); - memcpy(bitboards, position.bitboards, sizeof(BitBoard) * 12); - memcpy(occupancies, position.occupancies, sizeof(BitBoard) * 3); - memcpy(ptHashKey, position.ptKeys, sizeof(HashKey) * 6); -} - -void UndoInfo::undoMove(Position& position, Move move){ - position.hashKey = hashKey; - position.pawnHashKey = pawnsHashKey; - position.nonPawnKeys[WHITE] = nonPawnsHashKey[WHITE]; - position.nonPawnKeys[BLACK] = nonPawnsHashKey[BLACK]; - memcpy(position.ptKeys, ptHashKey, sizeof(HashKey) * 6); - position.enPassant = enPassant; - position.castle = castle; - position.fiftyMove = fiftyMove; - position.totalPly = totalPly; - position.plyFromNull = plyFromNull; - position.side = side; - position.threats = threats; - - Piece piece = movePiece(move); - Piece captured = moveCapture(move); - Piece aux = isCastling(move) ? (R + 6 * position.side) : movePromotion(move); - // We will now regenerate the bitboards. One thing to note is that captured and aux may be NOPIECE (12) - // In that case, we will not change the bitboard. We will do this in a fast and branchless way. - captured *= captured != NOPIECE; - aux *= aux != NOPIECE; - // So that we don't have to do a lot of if statements. Instead, if the piece is NOPIECE, it will become 0 (P) which means we will just make two extra copies, - // which won't in fact change anything. - position.bitboards[piece] = bitboards[piece]; - position.bitboards[captured] = bitboards[captured]; - position.bitboards[aux] = bitboards[aux]; - position.checkers = checkers; - memcpy(position.psqtScores, psqtScores, sizeof(PScore) * 8); - memcpy(position.occupancies, occupancies, sizeof(BitBoard) * 3); -} - -void UndoInfo::undoNullMove(Position& position){ - position.hashKey = hashKey; - position.pawnHashKey = pawnsHashKey; - position.nonPawnKeys[WHITE] = nonPawnsHashKey[WHITE]; - position.nonPawnKeys[BLACK] = nonPawnsHashKey[BLACK]; - memcpy(position.ptKeys, ptHashKey, sizeof(HashKey) * 6); - position.enPassant = enPassant; - position.castle = castle; - position.fiftyMove = fiftyMove; - position.totalPly = totalPly; - position.plyFromNull = plyFromNull; - position.side = side; - position.checkers = checkers; - position.threats = threats; -} diff --git a/src/Position.h b/src/Position.h deleted file mode 100644 index 7da5f5e..0000000 --- a/src/Position.h +++ /dev/null @@ -1,274 +0,0 @@ -#pragma once -#include "move.h" -#include -#include "BBmacros.h" -#include "movegen.h" - -// We love forward decl -struct SStack; - -// TTmove is always first - -// Followed by captures / promotions / promocaptures / enpassants -#define GOODNOISYMOVE 10000000LL -// Followed by killers and counter moves -#define KILLER1SCORE 8999999LL -#define KILLER2SCORE 8999998LL -#define COUNTERSCORE 8999997LL -// Followed by quiet moves -#define QUIETSCORE 1000000LL -// Followed by bad noisy moves -#define BADNOISYMOVE 16384LL - -constexpr Score pieceValues[15] = { - 100, 422, 422, 642, 1015, 0, // White pieces - 100, 422, 422, 642, 1015, 0, // Black pieces - 0, 0, 0 // Padding for special cases -}; - -struct Position{ - - BitBoard bitboards[12]; - BitBoard occupancies[3]; - BitBoard checkers; - U8 side; - U8 enPassant; - U8 fiftyMove; // 50 move rule counter, number of plies since the last irreversible move - Ply totalPly; // Total number of plies since the start of the game - Ply plyFromNull; // Ply from the last null move (see Null Move Pruning for more information) - U8 castle; - BitBoard threats; - HashKey hashKey; - HashKey pawnHashKey; - HashKey nonPawnKeys[2]; - HashKey ptKeys[6]; - PScore psqtScores[8]; // PSQT score, incrementally updated. - - // The default constructor instantiates the position with the standard chess starting position. - Position(); - - // The FEN constructor instantiates the position with the FEN string. - Position(const char* fen); - - /** - * @brief The Position::generateHashKey function generates the hash key of the position from scratch. - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - * @return The generated hashKey - */ - HashKey generateHashKey(); - - /** - * @brief The Position::generatePawnHashKey function generates the hash key of the pawn structure from scratch. - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ - HashKey generatePawnHashKey(); - - /** - * @brief The Position::generateNonPawnHashKey function generates the hash key of the non pawn structure from scratch, for a given side. - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ - HashKey generateNonPawnHashKey(const bool side); - - /** - * @brief The Position::generatePtHashKey function generates the hash key for a single pt from scratch. - * @tparam The pt to generate - * @note This function is called by the constructors. Otherwise the hash gets incrementally updated. - */ - template - HashKey generatePtHashKey(); - - /** - * @brief The Position::print function prints the position to stdout. - */ - void print(); - - /** - * @brief The wipe function wipes the position. - */ - void wipe(); - - void generateThreats(); - /** - * @brief The hasNonPawns function checks if the current side to move has non-pawn material. - * @return true if the position has non-pawn material, false otherwise. - */ - bool hasNonPawns(); - - /** - * @brief The mayBeZugzwang function tries to detect positions where reductions may be unsafe. - * @return True if the position is not to prune, false otherwise. - */ - bool mayBeZugzwang(); - - /** - * @brief The parseFEN function parses a FEN string, and places the pieces on the board. It also sets the turn, castling rights, en passant square, half move clock and full move number. - * It is filled with sanity checks, and will print an error message containing the error if it finds one. - * @param fen The FEN string to parse. - * @return True if the FEN string was parsed successfully, false otherwise (state of the position is undefined). - */ - bool parseFEN(char* FEN); - - /** - * @brief The isSquareAttacked function returns true if the given square is attacked by the given side. - * @param square The square to check. - * @param side The side to check. - * @return True if the square is attacked, false otherwise. - */ - bool isSquareAttacked(U8 square, U8 side); - - /** - * @brief The attacksToPre function returns a bitboard with all the attackers to a square. - * @param square The square to check. - * @param occupancy an already calculated occupancy - * @param diagonalAttackers an already calculated diagonal attackers - * @param orthogonalAttackers an already calculated orthogonal attackers - * @return A bitboard with all the attackers to the square. - * @TODO: diagonal and orthogonal attackers can be passed as parameters as they are already calculated - */ - inline BitBoard attacksToPre(Square square, BitBoard occupancy, BitBoard diagonalAttackers, BitBoard orthogonalAttackers); - - /** - * @brief The checkers function calculate current position checking pieces. - * @return A bitboard with all checker pieces - */ - inline BitBoard calculateCheckers(){ - const Square king = lsb(bitboards[K + 6 * side]); - const BitBoard* them = bitboards + 6 * (!side); - return (pawnAttacks[side][king] & them[P]) | - (knightAttacks[king] & them[N]) | - (getBishopAttack(king, occupancies[BOTH]) & (them[B] | them[Q])) | - (getRookAttack(king, occupancies[BOTH]) & (them[R] | them[Q])) ; - } - - /** - * @brief The makeMove function makes a move on the board. - * @param move The move to make. - * @return True if the move was made, false otherwise (state of the position is undefined). - */ - bool makeMove(Move move); - - /** - * @brief The makeNullMove function makes a null move on the board. - */ - void makeNullMove(); - - /** - * @brief The generateMoves function generates all pseudo legal moves for the current side. - * @param moveList The moveList to fill with the generated moves. - * @param ss The SStack to get the search information from (useful for move ordering heuristics). - */ - void generateMoves(MoveList& moveList, SStack* ss); - - /** - * @brief The generateCaptures function generates all pseud legal captures for the current side. - * @param moveList The moveList to fill with the generated moves. - */ - void generateCaptures(MoveList &moveList); - - /** - * @brief The generateUnsortedMoves function generates all pseudo legal moves for the current side. Used for perft testing (when we don't care about the move ordering). - * @param moveList The moveList to fill with the generated moves. - */ - void generateUnsortedMoves(MoveList &moveList); - - /** - * @brief The pieceOn function returns the piece on a square. If the square is empty, NOPIECE is returned. - * @param square The square to check. - * @return The piece on the square. - */ - inline Piece pieceOn(Square square) { - // We will do a branchless lookup - // We will have a "result" variable that will contain the piece on the square - Piece result = p + (!testBit(occupancies[WHITE], square)) * 6; // If the piece is black, we add 6 to the result. Also, if the square is empty, the result will be 6 which added to p is 6+6=12 (NOPIECE) - // We will subtract the piece code once we find it - result -= (p - P) * testBit(bitboards[P] | bitboards[p], square); - result -= (p - N) * testBit(bitboards[N] | bitboards[n], square); - result -= (p - B) * testBit(bitboards[B] | bitboards[b], square); - result -= (p - R) * testBit(bitboards[R] | bitboards[r], square); - result -= (p - Q) * testBit(bitboards[Q] | bitboards[q], square); - result -= (p - K) * testBit(bitboards[K] | bitboards[k], square); - return result; // If no piece was found, the result will remain NOPIECE - } - - /** - * @brief The legalizeTTMove function verifies if the TT move is Legal - * @param move The move to check - * @returns 0 if move wasnt legal, a legal move otherwise - */ - Move legalizeTTMove(Move move); - - inline void addEp(MoveList *ml, ScoredMove move); - template - inline void addPromoCapture(MoveList *ml, ScoredMove move, Piece movedPiece, Piece capturedPiece); - - inline void addCapture(MoveList *ml, ScoredMove move, Piece movedPiece, Piece capturedPiece); - template - inline void addPromotion(MoveList *ml, ScoredMove move); - - inline void addQuiet(MoveList *ml, ScoredMove move, Square source, Square target, Move killer1, Move killer2, Move counterMove, const S16 *ply1contHist, const S16 *ply2contHist, const S16 *ply4contHist); - - inline void addUnsorted(MoveList *ml, ScoredMove move); - - /** - * @brief The getFEN function returns the FEN string of the current position - * @return The FEN string of the current position - */ - std::string getFEN(); - - /** - * @brief The SEE function evaluates a move using the Static Exchange Evaluation algorithm. - * @param move The move to evaluate. - * @param threshold The threshold score. - * @return true if the move beats the threshold, false otherwise. - */ - bool SEE(const Move move, const Score threshold); - - bool inCheck(); - - bool insufficientMaterial(); - - void reflect(); -}; - -/** - * @brief The UndoInfo class contains all the information needed to undo a move. - * @note This class is used by the search to store the information needed to undo a move. - */ -struct UndoInfo { - // Irreversible information - HashKey hashKey; - HashKey pawnsHashKey; - HashKey nonPawnsHashKey[2]; - HashKey ptHashKey[6]; - Square enPassant; - U8 castle; - U8 fiftyMove; - Ply totalPly; - Ply plyFromNull; - PScore psqtScores[8]; - U8 side; - BitBoard threats; - // Reversible information - BitBoard bitboards[12]; - BitBoard occupancies[3]; - BitBoard checkers; - /** - * @brief The constructor of the UndoInfo class. - * @param position The position to store the information from. - */ - UndoInfo(Position& position); - - /** - * @brief The undoMove function undoes a move. - * @param position The position to undo the move on. - * @param move The move to undo. - */ - void undoMove(Position& position, Move move); - - /** - * @brief The undoNullMove function undoes a null move. - * @param position The position to undo the null move on. - */ - void undoNullMove(Position& position); - -}; \ No newline at end of file diff --git a/src/bench.cpp b/src/bench.cpp deleted file mode 100644 index 480cb4f..0000000 --- a/src/bench.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "types.h" -#include "Game.h" -#include "tables.h" -#include "tt.h" -#include "uci.h" -const char *benchmarkfens[50] = { - "r3k2r/2pb1ppp/2pp1q2/p7/1nP1B3/1P2P3/P2N1PPP/R2QK2R w KQkq a6 0 14", - "4rrk1/2p1b1p1/p1p3q1/4p3/2P2n1p/1P1NR2P/PB3PP1/3R1QK1 b - - 2 24", - "r3qbrk/6p1/2b2pPp/p3pP1Q/PpPpP2P/3P1B2/2PB3K/R5R1 w - - 16 42", - "6k1/1R3p2/6p1/2Bp3p/3P2q1/P7/1P2rQ1K/5R2 b - - 4 44", - "8/8/1p2k1p1/3p3p/1p1P1P1P/1P2PK2/8/8 w - - 3 54", - "7r/2p3k1/1p1p1qp1/1P1Bp3/p1P2r1P/P7/4R3/Q4RK1 w - - 0 36", - "r1bq1rk1/pp2b1pp/n1pp1n2/3P1p2/2P1p3/2N1P2N/PP2BPPP/R1BQ1RK1 b - - 2 10", - "3r3k/2r4p/1p1b3q/p4P2/P2Pp3/1B2P3/3BQ1RP/6K1 w - - 3 87", - "2r4r/1p4k1/1Pnp4/3Qb1pq/8/4BpPp/5P2/2RR1BK1 w - - 0 42", - "4q1bk/6b1/7p/p1p4p/PNPpP2P/KN4P1/3Q4/4R3 b - - 0 37", - "2q3r1/1r2pk2/pp3pp1/2pP3p/P1Pb1BbP/1P4Q1/R3NPP1/4R1K1 w - - 2 34", - "1r2r2k/1b4q1/pp5p/2pPp1p1/P3Pn2/1P1B1Q1P/2R3P1/4BR1K b - - 1 37", - "r3kbbr/pp1n1p1P/3ppnp1/q5N1/1P1pP3/P1N1B3/2P1QP2/R3KB1R b KQkq b3 0 17", - "8/6pk/2b1Rp2/3r4/1R1B2PP/P5K1/8/2r5 b - - 16 42", - "1r4k1/4ppb1/2n1b1qp/pB4p1/1n1BP1P1/7P/2PNQPK1/3RN3 w - - 8 29", - "8/p2B4/PkP5/4p1pK/4Pb1p/5P2/8/8 w - - 29 68", - "3r4/ppq1ppkp/4bnp1/2pN4/2P1P3/1P4P1/PQ3PBP/R4K2 b - - 2 20", - "5rr1/4n2k/4q2P/P1P2n2/3B1p2/4pP2/2N1P3/1RR1K2Q w - - 1 49", - "1r5k/2pq2p1/3p3p/p1pP4/4QP2/PP1R3P/6PK/8 w - - 1 51", - "q5k1/5ppp/1r3bn1/1B6/P1N2P2/BQ2P1P1/5K1P/8 b - - 2 34", - "r1b2k1r/5n2/p4q2/1ppn1Pp1/3pp1p1/NP2P3/P1PPBK2/1RQN2R1 w - - 0 22", - "r1bqk2r/pppp1ppp/5n2/4b3/4P3/P1N5/1PP2PPP/R1BQKB1R w KQkq - 0 5", - "r1bqr1k1/pp1p1ppp/2p5/8/3N1Q2/P2BB3/1PP2PPP/R3K2n b Q - 1 12", - "r1bq2k1/p4r1p/1pp2pp1/3p4/1P1B3Q/P2B1N2/2P3PP/4R1K1 b - - 2 19", - "r4qk1/6r1/1p4p1/2ppBbN1/1p5Q/P7/2P3PP/5RK1 w - - 2 25", - "r7/6k1/1p6/2pp1p2/7Q/8/p1P2K1P/8 w - - 0 32", - "r3k2r/ppp1pp1p/2nqb1pn/3p4/4P3/2PP4/PP1NBPPP/R2QK1NR w KQkq - 1 5", - "3r1rk1/1pp1pn1p/p1n1q1p1/3p4/Q3P3/2P5/PP1NBPPP/4RRK1 w - - 0 12", - "5rk1/1pp1pn1p/p3Brp1/8/1n6/5N2/PP3PPP/2R2RK1 w - - 2 20", - "8/1p2pk1p/p1p1r1p1/3n4/8/5R2/PP3PPP/4R1K1 b - - 3 27", - "8/4pk2/1p1r2p1/p1p4p/Pn5P/3R4/1P3PP1/4RK2 w - - 1 33", - "8/5k2/1pnrp1p1/p1p4p/P6P/4R1PK/1P3P2/4R3 b - - 1 38", - "8/8/1p1kp1p1/p1pr1n1p/P6P/1R4P1/1P3PK1/1R6 b - - 15 45", - "8/8/1p1k2p1/p1prp2p/P2n3P/6P1/1P1R1PK1/4R3 b - - 5 49", - "8/8/1p4p1/p1p2k1p/P2npP1P/4K1P1/1P6/3R4 w - - 6 54", - "8/8/1p4p1/p1p2k1p/P2n1P1P/4K1P1/1P6/6R1 b - - 6 59", - "8/5k2/1p4p1/p1pK3p/P2n1P1P/6P1/1P6/4R3 b - - 14 63", - "8/1R6/1p1K1kp1/p6p/P1p2P1P/6P1/1Pn5/8 w - - 0 67", - "1rb1rn1k/p3q1bp/2p3p1/2p1p3/2P1P2N/PP1RQNP1/1B3P2/4R1K1 b - - 4 23", - "4rrk1/pp1n1pp1/q5p1/P1pP4/2n3P1/7P/1P3PB1/R1BQ1RK1 w - - 3 22", - "r2qr1k1/pb1nbppp/1pn1p3/2ppP3/3P4/2PB1NN1/PP3PPP/R1BQR1K1 w - - 4 12", - "2r2k2/8/4P1R1/1p6/8/P4K1N/7b/2B5 b - - 0 55", - "6k1/5pp1/8/2bKP2P/2P5/p4PNb/B7/8 b - - 1 44", - "2rqr1k1/1p3p1p/p2p2p1/P1nPb3/2B1P3/5P2/1PQ2NPP/R1R4K w - - 3 25", - "r1b2rk1/p1q1ppbp/6p1/2Q5/8/4BP2/PPP3PP/2KR1B1R b - - 2 14", - "6r1/5k2/p1b1r2p/1pB1p1p1/1Pp3PP/2P1R1K1/2P2P2/3R4 w - - 1 36", - "rnbqkb1r/pppppppp/5n2/8/2PP4/8/PP2PPPP/RNBQKBNR b KQkq c3 0 2", - "2rr2k1/1p4bp/p1q1p1p1/4Pp1n/2PB4/1PN3P1/P3Q2P/2RR2K1 w - f6 0 20", - "3br1k1/p1pn3p/1p3n2/5pNq/2P1p3/1PN3PP/P2Q1PB1/4R1K1 w - - 0 23", - "2r2b2/5p2/5k2/p1r1pP2/P2pB3/1P3P2/K1P3R1/7R w - - 23 93" -}; - -S32 benchmark(Depth depth){ - initTT(); - U64 nodes = 0; - U64 totalTime = 0; - Game game; - double avgNodeProportion = 0; - for(int i = 0; i < 50; i++){ - std::cout << "Benchmarking position " << i << std::endl; - U64 currTime = getTime64(); - game.reset(); - game.searchMode = 1; - game.depth = depth; - game.parseFEN((char*)benchmarkfens[i]); - game.hardNodesLimit = 0xFFFFFFFFFFFFFFFF; - game.startSearch(false); - nodes += game.nodes; - Move bestMove = pvTable[0][0]; // Bench never returns half searches, hence this is always a bestmove - avgNodeProportion += (double)game.nodesPerMoveTable[indexFromTo(moveSource(bestMove), moveTarget(bestMove))] / (double)game.nodes; - totalTime += getTime64() - currTime; - } - game.reset(); - std::cout << "Time: " << totalTime << " ms - Mainline nodecount proportion: " << avgNodeProportion / 50 << std::endl; - - std::cout << nodes << " nodes " << (nodes * 1000) / (1 + totalTime) << " nps" << std::endl; - - return 0; -} \ No newline at end of file diff --git a/src/bench.h b/src/bench.h deleted file mode 100644 index e3ee963..0000000 --- a/src/bench.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "types.h" - -S32 benchmark(Depth depth); \ No newline at end of file diff --git a/src/build.mk b/src/build.mk deleted file mode 100644 index 2729fca..0000000 --- a/src/build.mk +++ /dev/null @@ -1,74 +0,0 @@ -TARGET ?= Release -OBJ_DIR = obj/$(TARGET) - -CPP_FILES := $(wildcard *.cpp) -OBJ_FILES = $(addprefix $(OBJ_DIR)/, $(CPP_FILES:.cpp=.o)) - -ifeq ($(OS),Windows_NT) -ifeq ($(CXX),clang++) -# disable msvc linker (beacuse bad) - LINKER := -fuse-ld=lld-link -endif -endif - -CXX ?= clang++ -CXXFLAGS := -Wall -Wextra -Wpedantic -std=c++20 -Wno-implicit-fallthrough -EXE ?= Perseus -CPU ?= default - -ifeq ($(TARGET), Release) -# -lm in g++ means to link the math library; in clang++ it means to link the library named 'm.lib' (which doesn't exist). -# since the math library *should* be linked by default it's being removed from the flags. in case of errors, add an if that adds it in case of g++. - CXXFLAGS += -funroll-loops -O3 -flto -fno-exceptions -DNDEBUG -else ifeq ($(TARGET), Debug) - CXXFLAGS += -g -O0 -fsanitize=address,undefined -fno-omit-frame-pointer -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -else - $(error "Unknown target: $(TARGET)") -endif - -ifeq ($(CPU), default) - CPU_FLAGS := -march=native -else ifeq ($(CPU), M64) - CPU_FLAGS := -m64 -mpopcnt -else ifeq ($(CPU), haswell) - CPU_FLAGS := -march=haswell -m64 -else ifeq ($(CPU), znver2) - CPU_FLAGS := -march=znver2 -else ifeq ($(CPU), native) - CPU_FLAGS := -march=native -else - $(error "Unknown CPU architecture: $(CPU)") -endif - -CXXFLAGS += $(CPU_FLAGS) - -.PHONY: all build dirs link clean - -all: build - -build: dirs $(OBJ_FILES) link - -dirs: -ifeq ($(OS),Windows_NT) - @if not exist $(subst /,\,$(OBJ_DIR)) mkdir $(subst /,\,$(OBJ_DIR)) -else - @mkdir -p $(OBJ_DIR) -endif - -$(OBJ_DIR)/%.o: %.cpp - @echo "Compiling $<" - @$(CXX) $(CXXFLAGS) -c $< -o $@ - -link: $(OBJ_FILES) - @echo "Linking" - @$(CXX) $(CXXFLAGS) $(LINKER) $(OBJ_FILES) -o $(EXE) - -clean: - @echo "Cleaning" -ifeq ($(OS),Windows_NT) - @if exist $(subst /,\,$(OBJ_DIR)) rmdir /s /q $(subst /,\,$(OBJ_DIR)) - @if exist $(EXE) del $(EXE) -else - @rm -rf $(OBJ_DIR) - @rm -f $(EXE) -endif diff --git a/src/constants.cpp b/src/constants.cpp deleted file mode 100644 index 9c03149..0000000 --- a/src/constants.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "constants.h" -#include "types.h" -#include - -std::vector& tunableParams() { - static std::vector tunableParams{}; - tunableParams.reserve(128); - return tunableParams; -} - -TunableParam& addTune(std::string name, S32 defaultValue, S32 minValue, S32 maxValue, float cEnd, float rEnd) { - tunableParams().emplace_back(name, defaultValue, minValue, maxValue, cEnd, rEnd); - return tunableParams().back(); -} \ No newline at end of file diff --git a/src/constants.h b/src/constants.h deleted file mode 100644 index 4c0e5e5..0000000 --- a/src/constants.h +++ /dev/null @@ -1,268 +0,0 @@ -#pragma once -#include "types.h" - -#include - -// The search-uci communication frequency. - -constexpr U64 comfrequency = 2047LL; // The search-uci communication frequency is expressed as 2^n - 1, and it will make the search communicate with the uci every 2^n nodes. - -// The mate scores are used to recognize if a score is a mate or not. -constexpr Score infinity = 32500; // The score considered infinite. -constexpr Score mateScore = 32000; // The score of mate in 0 ply. -constexpr Score mateValue = 31500; // The score above which a score is to be considered a mate. -constexpr Score noScore = -32500; // The score considered no score. -constexpr Move noMove = 0; // The move considered no move. - -// The draw scores are used to recognize if a score is a draw or not. -constexpr Score drawScore = 0; // The score of a draw. - -// The score above which the position is theoretically won. -constexpr Score KNOWNWIN = 12000; // The score above which the position is theoretically won. - -// The maximum ply the engine will search to. -constexpr U16 maxPly = 128; // The maximum ply the engine will search to. - -// The number of colors and squares on the board. -constexpr int NUM_COLORS = 2; // The number of colors. -constexpr int NUM_SQUARES = 64; // The number of squares on the board. -constexpr int NUM_PIECES = 12; // The number of piece types (color sensitive). -constexpr int NUM_PIECE_TYPES = 6; // The number of piece types (color insensitive). - -// ENUMS - -// The enum of side to move. -enum Side { - // White to move. - WHITE = 0, - // Black to move. - BLACK = 1, - // Unset or both to move. - BOTH -}; - -// The enum of castle rights -enum CastleRights { - // White castle kingside. - WK = 1, - // White castle queenside. - WQ = 2, - // Black castle kingside. - BK = 4, - // Black castle queenside. - BQ = 8 -}; - -// The enum of pieces -enum Pieces { - P, N, B, R, Q, K, p, n, b, r, q, k, NOPIECE -}; - - - -// The enum of squares. -enum Squares { - a8, b8, c8, d8, e8, f8, g8, h8, - a7, b7, c7, d7, e7, f7, g7, h7, - a6, b6, c6, d6, e6, f6, g6, h6, - a5, b5, c5, d5, e5, f5, g5, h5, - a4, b4, c4, d4, e4, f4, g4, h4, - a3, b3, c3, d3, e3, f3, g3, h3, - a2, b2, c2, d2, e2, f2, g2, h2, - a1, b1, c1, d1, e1, f1, g1, h1, noSquare -}; - -// FUNCTIONALITY SYMBOL DEFINITIONS - -// SEARCH TECHNIQUES -/* -- TT PARAMETERS */ -#define TTEXACTDEPTHBONUS 0 // The depth bonus for exact entries in the transposition table. - - -/* -- SEARCH TECHNIQUES -- */ -#define ENABLETTSCORING true // If true the transposition table is used for cutoffs. The transposition table is automatically implemented in the search function if this is true. -#define DETECTREPETITION true // If true the repetition detection is used. The repetition detection is automatically implemented in the search function if this is true. -#define ENABLEPREFETCHING true // If true the prefetching is used. The prefetching is automatically implemented in the search function if this is true. - -/* -- PRUNING TECHNIQUES -- */ -#define ENABLENMP true // If true the null move pruning is used. The null move pruning is automatically implemented in the search function if this is true. - -/* -- MOVE ORDERING TECHNIQUES -- */ -#define ENABLEMVVLVASORTING true // If true the move ordering is sorted by the MVV/LVA heuristic. The move ordering is automatically implemented in the search function if this is true. -#define ENABLEPROMOTIONSORTING true // If true the move ordering is sorted by the promotion heuristic. The move ordering is automatically implemented in the search function if this is true. -#define ENABLEPSQTDIFFSORTING true // If true the move ordering is sorted by the difference in the piece square tables. The move ordering is automatically implemented in the search function if this is true. -#define ENABLEHISTORYHEURISTIC true // If true the history heuristic is used. The history heuristic is automatically implemented in the search function if this is true. -#define ENABLETTORDERING true // If true the transposition table is used for move ordering. The transposition table is automatically implemented in the search function if this is true. ENABLETTSCORING must be true for this to work. -#define ENABLEKILLERHEURISTIC true // If true the killer heuristic is used. The killer heuristic is automatically implemented in the search function if this is true. -#define ENABLECOUNTERMOVEHEURISTIC true // If true the counter move heuristic is used. The counter move heuristic is automatically implemented in the search function if this is true. -#define ENABLEBETTERHISTORYFORMULA true // If true the better history formula is used. The better history formula is automatically implemented in the search function if this is true. - -// QUIESCENCE TECHNIQUES -#define ENABLEQUIESCENCESEARCH true // If true the quiescence search is used. The quiescence search is automatically implemented in the search function if this is true. -#define EVASIONSINQUIESCENCE true // If true the search function will search for evasions in quiescence search. Quiescence search must be enabled for this to work. -#define DODELTAPRUNING true // If true the delta pruning is used. Quiescence search must be enabled for this to work. - -// DEBUGGING SYMBOL DEFINITIONS -#define DEBUG false // If true the debugging is used. The debugging is automatically implemented in the code if this is true. -#define ASSERTS true // If true the asserts are used. The asserts are automatically implemented in the code if this is true. -#define LOGROOTMOVEDEPTH 127 // The depth at which the root moves are logged. Setting this to >= 128 will disable logging. - -struct TunableParam { - std::string name; - S32 defaultValue; - S32 minValue; - S32 maxValue; - float cEnd; - float rEnd; - S32 value; - - inline TunableParam(std::string name, S32 defaultValue, S32 minValue, S32 maxValue, float cEnd, float rEnd) - : name(name), defaultValue(defaultValue), minValue(minValue), maxValue(maxValue), cEnd(cEnd), rEnd(rEnd), value(defaultValue){} - - inline operator int() const { return value; } - inline TunableParam& operator=(int value) { - this->value = value; - return *this; - } -}; - -std::vector& tunableParams(); -TunableParam& addTune(std::string name, S32 defaultValue, S32 minValue, S32 maxValue, float cEnd, float rEnd); - -//#define TUNE - -#ifdef TUNE - #define TUNE_PARAM(name, defaultValue, minValue, maxValue, cEnd, rEnd) \ - inline const TunableParam& tuned_##name = addTune(#name, defaultValue, minValue, maxValue, cEnd, rEnd); \ - inline S32 name() { return tuned_##name.value; } -#else - #define TUNE_PARAM(name, defaultValue, minValue, maxValue, cEnd, rEnd); \ - constexpr S32 name() { return defaultValue; } -#endif - -// Easy way to enable / disable some params from being modifiable -#define NO_TUNE_PARAM(name, defaultValue, minValue, maxValue, cEnd, rEnd); \ - constexpr S32 name() { return defaultValue; } - -// History stuff -TUNE_PARAM(maxHistoryBonus, 2272, 1, 4096, 128, 0.002); -TUNE_PARAM(historyBonusQuadDepth, 9, 1, 32, 1, 0.002); -TUNE_PARAM(historyBonusLinDepth, 216, 1, 1024, 16, 0.002); -TUNE_PARAM(historyBonusOffset, -340, -1024, 1024, 52, 0.002); - -TUNE_PARAM(maxHistoryMalus, 710, 1, 4096, 128, 0.002); -TUNE_PARAM(historyMalusQuadDepth, 4, 1, 32, 1, 0.002); -TUNE_PARAM(historyMalusLinDepth, 266, 1, 1024, 16, 0.002); -TUNE_PARAM(historyMalusOffset, 26, -1024, 1024, 52, 0.002); - -// LMR table values -TUNE_PARAM(lmrDepthValue, 1011, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrMoveValue, 1128, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrA0, 697, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrC0, -324, -1000, 1000, 100, 0.002); -TUNE_PARAM(lmrA1, 752, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrC1, 763, 500, 1500, 50, 0.002); - -// LMR additionals -TUNE_PARAM(lmrCieckA, 4401, 2048, 8192, 256, 0.002) -TUNE_PARAM(lmrCieckB, 1489, 500, 2500, 98, 0.002) -TUNE_PARAM(lmrCieckC, 741, 128, 1024, 48, 0.002) -TUNE_PARAM(lmrPV, 1169, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrExpectedDecent, 694, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrQuietHistoryDivisor, 8396, 2000, 14000, 500, 0.002) -TUNE_PARAM(lmrQuietCutNode, 1978, 250, 2750, 125, 0.002); -TUNE_PARAM(lmrQuietTTPV, 980, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrBadNoisyCutNode, 648, 250, 2750, 125, 0.002); -TUNE_PARAM(lmrNoisyHistoryDivisorA, 5192, 2000, 14000, 500, 0.002) -TUNE_PARAM(lmrNoisyHistoryDivisorB, 6587, 2000, 14000, 500, 0.002) - -// Deeper / shallower -TUNE_PARAM(doDeeperMargin, 33, 10, 50, 2, 0.002) - -// PVS SEE -TUNE_PARAM(pvsSeeThresholdNoisy, -16, -160, -10, 6, 0.002) -TUNE_PARAM(pvsSeeThresholdQuiet, -109, -160, -10, 6, 0.002) -NO_TUNE_PARAM(pvsSeeMaxDepth, 7, 5, 10, 0.5, 0.002) - -// LMP values -TUNE_PARAM(lmpA0, 597, 250, 1750, 64, 0.002); -TUNE_PARAM(lmpC0, 1929, 500, 5000, 198, 0.002); -TUNE_PARAM(lmpA1, 1023, 250, 1750, 64, 0.002); -TUNE_PARAM(lmpC1, 2795, 500, 5000, 198, 0.002); - -// RFP values -TUNE_PARAM(futilityMarginDelta, 99, 45, 145, 4, 0.002); -NO_TUNE_PARAM(RFPDepth, 8, 5, 10, .5, 0.002); - -// NMP values -TUNE_PARAM(nmpMarginBias, 177, 100, 300, 8, 0.002); -TUNE_PARAM(nmpDepthMargin, 26, 10, 50, 2, 0.002); -NO_TUNE_PARAM(nmpDepthDivisor, 4, 2, 6, .5, 0.002); -TUNE_PARAM(nmpScoreDivisor, 222, 100, 300, 8, 0.002); -NO_TUNE_PARAM(nmpQ1, 3, 1, 5, .5, 0.002); -NO_TUNE_PARAM(nmpQ2, 3, 0, 5, .5, 0.002); - -// Razoring value -TUNE_PARAM(razorQ1, 97, -200, 200, 16, 0.002); -TUNE_PARAM(razorQ2, 239, 100, 500, 16, 0.002); -NO_TUNE_PARAM(razorDepth, 3, 2, 5, .5, 0.002); - -// Singular Extensions -TUNE_PARAM(singularDepthMultiplier, 8, 1, 30, 1, 0.002); -TUNE_PARAM(doubleExtensionMargin, 21, 1, 50, 2, 0.002); -NO_TUNE_PARAM(singularSearchDepth, 7, 5, 10, .5, 0.002); - -// History Pruning values -TUNE_PARAM(historyPruningMultiplier, -1508, -5120, -1024, 205, 0.002); -TUNE_PARAM(historyPruningBias, 157, -2048, 2048, 205, 0.002); - -// IIR values -NO_TUNE_PARAM(IIRDepth, 6, 3, 8, .5, 0.002); - -// FFP values -TUNE_PARAM(futPruningMultiplier, 49, 30, 130, 4, 0.002); -TUNE_PARAM(futPruningAdd, 254, 150, 350, 8, 0.002); -NO_TUNE_PARAM(futPruningDepth, 9, 6, 10, 0.5, 0.002); -TUNE_PARAM(qsFutilityMargin, 77, 0, 150, 8, 0.002) - -// Move ordering values -TUNE_PARAM(captScoreMvvMultiplier, 14, 8, 32, 1, 0.002) - -// Time management values -TUNE_PARAM(timeTmA, 141, 10, 200, 2, 0.002) -TUNE_PARAM(timeTmB, 989, 0, 1000, 13, 0.002) -TUNE_PARAM(timeTmOptimScale, 420, 100, 1000, 11, 0.002) -TUNE_PARAM(nodesTmMax, 1867, 1500, 2500, 13, 0.002) -TUNE_PARAM(nodesTmMul, 1359, 750, 1500, 10, 0.002) - -// CorrHist scale values -TUNE_PARAM(MAXCORRHISTUNSCALED, 39, 16, 128, 8, 0.002) -TUNE_PARAM(MAXCORRHISTMILLIUPDATE, 193, 128, 512, 18, 0.002) - -// CorrHist correction values -TUNE_PARAM(pawnCorrWeight, 1310, 0, 2048, 102, 0.002) -TUNE_PARAM(nonPawnCorrWeight, 1128, 0, 2048, 102, 0.002) -TUNE_PARAM(T0CorrWeight, 1160, 0, 2048, 102, 0.002) -TUNE_PARAM(T1CorrWeight, 885, 0, 2048, 102, 0.002) -TUNE_PARAM(T2CorrWeight, 1003, 0, 2048, 102, 0.002) -TUNE_PARAM(T3CorrWeight, 1125, 0, 2048, 102, 0.002) -TUNE_PARAM(T4CorrWeight, 1230, 0, 2048, 102, 0.002) -TUNE_PARAM(T5CorrWeight, 873, 0, 2048, 102, 0.002) -TUNE_PARAM(T6CorrWeight, 1116, 0, 2048, 102, 0.002) -TUNE_PARAM(T7CorrWeight, 934, 0, 2048, 102, 0.002) -TUNE_PARAM(T8CorrWeight, 1013, 0, 2048, 102, 0.002) -TUNE_PARAM(T9CorrWeight, 1173, 0, 2048, 102, 0.002) - -// CorrHist update values -TUNE_PARAM(pawnCorrUpdate, 1061, 0, 2048, 102, 0.002) -TUNE_PARAM(nonPawnCorrUpdate, 1054, 0, 2048, 102, 0.002) -TUNE_PARAM(T0CorrUpdate, 828, 0, 2048, 102, 0.002) -TUNE_PARAM(T1CorrUpdate, 877, 0, 2048, 102, 0.002) -TUNE_PARAM(T2CorrUpdate, 1016, 0, 2048, 102, 0.002) -TUNE_PARAM(T3CorrUpdate, 1047, 0, 2048, 102, 0.002) -TUNE_PARAM(T4CorrUpdate, 1124, 0, 2048, 102, 0.002) -TUNE_PARAM(T5CorrUpdate, 1042, 0, 2048, 102, 0.002) -TUNE_PARAM(T6CorrUpdate, 903, 0, 2048, 102, 0.002) -TUNE_PARAM(T7CorrUpdate, 1106, 0, 2048, 102, 0.002) -TUNE_PARAM(T8CorrUpdate, 1248, 0, 2048, 102, 0.002) -TUNE_PARAM(T9CorrUpdate, 924, 0, 2048, 102, 0.002) diff --git a/src/evaluation.cpp b/src/evaluation.cpp deleted file mode 100644 index 71aa77d..0000000 --- a/src/evaluation.cpp +++ /dev/null @@ -1,1908 +0,0 @@ -#include "evaluation.h" -#include "tables.h" -#include "tt.h" -#include "movegen.h" -#include "zobrist.h" -#include "types.h" -#include -#include -#include -#include -#include -#include - -PScore PSQTs[2][12][64]; - -PawnEvalHashEntry pawnEvalHash[PAWNHASHSIZE]; - - -void initTables() { - for(Square square = a8; square < noSquare; square++) { - // White - PSQTs[0][P][square] = pawnTable[0][square] ; // + materialValues[P]; - PSQTs[1][P][square] = pawnTable[1][square] ; // + materialValues[P]; - PSQTs[0][N][square] = knightTable[0][square] ; // + materialValues[N]; - PSQTs[1][N][square] = knightTable[1][square] ; // + materialValues[N]; - PSQTs[0][B][square] = bishopTable[0][square] ; // + materialValues[B]; - PSQTs[1][B][square] = bishopTable[1][square] ; // + materialValues[B]; - PSQTs[0][R][square] = rookTable[0][square] ; // + materialValues[R]; - PSQTs[1][R][square] = rookTable[1][square] ; // + materialValues[R]; - PSQTs[0][Q][square] = queenTable[0][square] ; // + materialValues[Q]; - PSQTs[1][Q][square] = queenTable[1][square] ; // + materialValues[Q]; - PSQTs[0][K][square] = kingTable[0][square]; - PSQTs[1][K][square] = kingTable[1][square]; - // Black - PSQTs[0][p][flipSquare(square)] = -PSQTs[0][P][square]; - PSQTs[1][p][flipSquare(square)] = -PSQTs[1][P][square]; - PSQTs[0][n][flipSquare(square)] = -PSQTs[0][N][square]; - PSQTs[1][n][flipSquare(square)] = -PSQTs[1][N][square]; - PSQTs[0][b][flipSquare(square)] = -PSQTs[0][B][square]; - PSQTs[1][b][flipSquare(square)] = -PSQTs[1][B][square]; - PSQTs[0][r][flipSquare(square)] = -PSQTs[0][R][square]; - PSQTs[1][r][flipSquare(square)] = -PSQTs[1][R][square]; - PSQTs[0][q][flipSquare(square)] = -PSQTs[0][Q][square]; - PSQTs[1][q][flipSquare(square)] = -PSQTs[1][Q][square]; - PSQTs[0][k][flipSquare(square)] = -PSQTs[0][K][square]; - PSQTs[1][k][flipSquare(square)] = -PSQTs[1][K][square]; - } -} - -constexpr PScore DOUBLEISOLATEDPEN = S(-14, -35); -constexpr PScore ISOLATEDPEN = S(-18, -20); -constexpr PScore BACKWARDPEN = S(-7, 8); -constexpr PScore DOUBLEDPEN = S(-20, -24); -constexpr PScore SUPPORTEDPHALANX = S(1, 10); -constexpr PScore ADVANCABLEPHALANX = S(7, 9); -constexpr PScore R_SUPPORTEDPHALANX = S(3, 0); -constexpr PScore R_ADVANCABLEPHALANX = S(4, 0); -constexpr PScore passedRankBonus[2][7] = { - {S(0, 0), S(10, -69), S(-5, -45), S(-1, 8), S(22, 64), S(45, 155), S(113, 229)}, - {S(0, 0), S(0, 0), S(8, -61), S(10, -5), S(57, 63), S(157, 177), S(395, 250)} -}; -constexpr PScore PASSEDPATHBONUS = S(-5, 23); -constexpr PScore candidateRankBonus[2][7] = { - {S(0, 0), S(-36, 4), S(-25, 22), S(-9, 60), S(5, 128), S(35, 107), S(0, 0)}, - {S(0, 0), S(0, 0), S(-7, 32), S(3, 67), S(47, 143), S(124, 170), S(0, 0)} -}; -constexpr PScore INNERSHELTER = S(3, -11); -constexpr PScore OUTERSHELTER = S(13, -7); -constexpr PScore BISHOPPAIR = S(18, 116); -constexpr PScore ROOKONOPENFILE = S(19, 8); -constexpr PScore ROOKONSEMIOPENFILE = S(24, 11); -constexpr PScore KNIGHTONEXTOUTPOST = S(31, 38); -constexpr PScore BISHOPONEXTOUTPOST = S(38, 4); -constexpr PScore KNIGHTONINTOUTPOST = S(24, 41); -constexpr PScore BISHOPONINTOUTPOST = S(37, -2); -constexpr PScore KNIGHTPROTECTOR = S(-7, -1); -constexpr PScore BISHOPPROTECTOR = S(-5, -3); -constexpr PScore BISHOPPAWNS = S(1, -3); -constexpr PScore THREATSAFEPAWN = S(46, -42); -constexpr PScore THREATPAWNPUSH = S(20, 39); -constexpr PScore PAWNHANGING = S(-1, -52); -constexpr PScore NONPAWNHANGING = S(-8, -40); -constexpr PScore PAWNTHREAT[2][5] = { - {S(11, -67), S(31, 76), S(28, 119), S(29, 42), S(8, 36)}, - {S(4, -26), S(11, 126), S(12, 165), S(23, 94), S(15, 96)} -}; -constexpr PScore KNIGHTTHREAT[2][5] = { - {S(8, 21), S(0, -28), S(27, 19), S(59, -13), S(39, 15)}, - {S(-7, 9), S(1, 20), S(26, 72), S(53, 57), S(42, 45)} -}; -constexpr PScore BISHOPTHREAT[2][5] = { - {S(14, 24), S(34, 25), S(-9, -36), S(58, -7), S(55, 27)}, - {S(2, 16), S(34, 74), S(-5, 14), S(51, 66), S(50, 77)} -}; -constexpr PScore ROOKTHREAT[2][5] = { - {S(3, 20), S(12, 47), S(22, 34), S(-7, -62), S(60, -17)}, - {S(-10, 4), S(3, 25), S(7, 21), S(0, -6), S(44, 38)} -}; -constexpr PScore QUEENTHREAT[2][5] = { - {S(12, -3), S(27, -4), S(27, 22), S(-2, -21), S(5, -142)}, - {S(-2, 7), S(7, -2), S(5, 13), S(1, 5), S(11, -121)} -}; -constexpr PScore KINGTHREAT = S(-5, -4); -constexpr PScore QUEENINFILTRATION = S(5, 2); -constexpr PScore INVASIONSQUARES = S(6, 7); -constexpr PScore RESTRICTEDSQUARES = S(4, 4); -constexpr PScore TEMPO = S(19, 25); - -constexpr PScore PAWNATTACKINNERRING = S(29, -332); -constexpr PScore KNIGHTATTACKINNERRING = S(82, -135); -constexpr PScore BISHOPATTACKINNERRING = S(118, 14); -constexpr PScore ROOKATTACKINNERRING = S(123, -3); -constexpr PScore QUEENATTACKINNERRING = S(83, -217); -constexpr PScore PAWNATTACKOUTERRING = S(76, -102); -constexpr PScore KNIGHTATTACKOUTERRING = S(83, 82); -constexpr PScore BISHOPATTACKOUTERRING = S(81, 129); -constexpr PScore ROOKATTACKOUTERRING = S(30, 15); -constexpr PScore QUEENATTACKOUTERRING = S(55, 183); -constexpr PScore NOQUEENDANGER = S(-865, -493); -constexpr PScore PINNEDSHELTERDANGER = S(103, -109); -constexpr PScore FLANKATTACKS[2] = {S(32, -62), S(40, -103), }; -constexpr PScore FLANKDEFENSES[2] = {S(-32, 23), S(-10, 18), }; -constexpr PScore SAFECHECK[4] = {S(307, -44), S(90, 87), S(232, 153), S(224, 47), }; -constexpr PScore ALLCHECKS[4] = {S(81, 7), S(33, 131), S(71, 32), S(11, 59), }; -constexpr PScore SAFETYINNERSHELTER = S(-54, -45); -constexpr PScore SAFETYOUTERSHELTER = S(-5, -232); -constexpr PScore INNERWEAKNESS = S(93, -17); -constexpr PScore OUTERWEAKNESS = S(15, 25); -constexpr PScore KSTEMPO = S(32, 57); - -constexpr Score COMPLEXITYPASSERS = 467; -constexpr Score COMPLEXITYPAWNS = 1105; -constexpr Score COMPLEXITYBLOCKEDPAIRS = -407; -constexpr Score COMPLEXITYPAWNTENSION = -758; -constexpr Score COMPLEXITYOUTFLANKING = -39; -constexpr Score COMPLEXITYINFILTRATION = -846; -constexpr Score COMPLEXITYPAWNBOTHFLANKS = 10166; -constexpr Score COMPLEXITYPAWNENDING = 13121; -constexpr Score COMPLEXITYALMOSTUNWINNABLE = -3231; -constexpr Score COMPLEXITYBIAS = -21141; - -// Function to access the table values -static inline S32 getKingSafetyFromTable(const std::array& table, int x) { - // Map x to the table index range - S32 index = ((x - MIN_X) * (KSTABLESIZE - 1) + (MAX_X - MIN_X)/2) / (MAX_X - MIN_X); - return table[std::clamp(index, 0, KSTABLESIZE-1)]; -} - -int getKingSafetyMg(int x) { - return getKingSafetyFromTable(kingSafetyMgTable, x); -} - -int getKingSafetyEg(int x) { - return getKingSafetyFromTable(kingSafetyEgTable, x); -} - -static inline constexpr BitBoard centralFiles = files(2) | files(3) | files(4) | files(5); - -template -//(bb, occ, pinned, mobilityArea, mobilityScore); -static inline void getMobilityFeat(const BitBoard (&bb)[12], BitBoard occCheck, const BitBoard pinned, const BitBoard mob, BitBoard &attackedByUs, BitBoard &ourMultiAttacks, BitBoard &ptAttacks, S8 *features, const Square kingSquare, const BitBoard kingRing, const BitBoard kingOuter, S32 &innerAttacks, S32 &outerAttacks, S32 &kingDist) { - constexpr Side us = pt < p ? WHITE : BLACK; - // constexpr Side them = us ? BLACK : WHITE; - BitBoard pieces = bb[pt] & ~pinned; - - // Consider diagonal xrays through our queens - if constexpr (pt == B || pt == Q) occCheck ^= bb[Q]; - else if constexpr (pt == b || pt == q) occCheck ^= bb[q]; - - // Consider cross xrays through our rooks - if constexpr (pt == R || pt == Q) occCheck ^= bb[R]; - else if constexpr (pt == r || pt == q) occCheck ^= bb[r]; - - // Iterate over all pieces of the given type - - while (pieces) { - BitBoard moves; - BitBoard mobMoves; - Square sq = popLsb(pieces); - if constexpr (pt == N || pt == n) { - moves = knightAttacks[sq]; - mobMoves = moves & mob; - U8 moveCount = popcount(mobMoves); - features[moveCount] += us == WHITE ? 1 : -1; - kingDist += chebyshevDistance[kingSquare][sq] * (us == WHITE ? 1 : -1); - } - else if constexpr (pt == B || pt == b) { // X-ray through our queens - moves = getBishopAttack(sq, occCheck); - mobMoves = moves & mob; - U8 moveCount = popcount(mobMoves); - features[moveCount] += us == WHITE ? 1 : -1; - kingDist += chebyshevDistance[kingSquare][sq] * (us == WHITE ? 1 : -1); - } - else if constexpr (pt == R || pt == r) { // X-ray through our queens and rooks - moves = getRookAttack(sq, occCheck); - mobMoves = moves & mob; - U8 moveCount = popcount(mobMoves); - features[moveCount] += us == WHITE ? 1 : -1; - } - else if constexpr (pt == Q || pt == q) { // X-ray through our queens - moves = getQueenAttack(sq, occCheck); - mobMoves = moves & mob; - U8 moveCount = popcount(mobMoves); - features[moveCount] += us == WHITE ? 1 : -1; - } - innerAttacks += popcount(mobMoves & kingRing); - outerAttacks += popcount(mobMoves & kingOuter); - ourMultiAttacks |= attackedByUs & moves; - attackedByUs |= moves; - ptAttacks |= moves; - } -} - -template -//(bb, occ, pinned, mobilityArea, mobilityScore); -static inline void mobility(const BitBoard *bb, BitBoard occCheck, const BitBoard pinned, const BitBoard mobilityArea, PScore &score, BitBoard &attackedByUs, BitBoard &ourMultiAttacks, BitBoard &ptAttacks, const Square kingSquare, const BitBoard kingRing, const BitBoard kingOuter, PScore &innerAttacks, PScore &outerAttacks){ - // constexpr Side them = us ? BLACK : WHITE; - BitBoard pieces = bb[pt] & ~pinned; // TODO: try to exclude xray through pinned pieces - - // Consider diagonal xrays through our queens - if constexpr (pt == B || pt == Q) occCheck ^= bb[Q]; - - // Consider cross xrays through our rooks - if constexpr (pt == R || pt == Q) occCheck ^= bb[R]; - - // Iterate over all pieces of the given type - - while (pieces) { - BitBoard moves; - BitBoard mobMoves; - Square sq = popLsb(pieces); - if constexpr (pt == N) { - moves = knightAttacks[sq]; - mobMoves = moves & mobilityArea; - U8 moveCount = popcount(mobMoves); - // Add the mobility score - score += knightMob[moveCount] + KNIGHTPROTECTOR * chebyshevDistance[kingSquare][sq]; - innerAttacks += KNIGHTATTACKINNERRING * popcount(mobMoves & kingRing); - outerAttacks += KNIGHTATTACKOUTERRING * popcount(mobMoves & kingOuter); - } - else if constexpr (pt == B) { - moves = getBishopAttack(sq, occCheck); - mobMoves = moves & mobilityArea; - U8 moveCount = popcount(mobMoves); // X-ray through our queens - // Add the mobility score - score += bishopMob[moveCount] + BISHOPPROTECTOR * chebyshevDistance[kingSquare][sq]; - innerAttacks += BISHOPATTACKINNERRING * popcount(mobMoves & kingRing); - outerAttacks += BISHOPATTACKOUTERRING * popcount(mobMoves & kingOuter); - } - else if constexpr (pt == R) { - moves = getRookAttack(sq, occCheck); - mobMoves = moves & mobilityArea; - U8 moveCount = popcount(mobMoves); // X-ray through our queens and rooks - // Add the mobility score - score += rookMob[moveCount]; - innerAttacks += ROOKATTACKINNERRING * popcount(mobMoves & kingRing); - outerAttacks += ROOKATTACKOUTERRING * popcount(mobMoves & kingOuter); - } - else if constexpr (pt == Q) { - moves = getQueenAttack(sq, occCheck); - mobMoves = moves & mobilityArea; - U8 moveCount = popcount(mobMoves); // X-ray through our queens - // Add the mobility score - score += queenMob[moveCount]; - innerAttacks += QUEENATTACKINNERRING * popcount(mobMoves & kingRing); - outerAttacks += QUEENATTACKOUTERRING * popcount(mobMoves & kingOuter); - } - ourMultiAttacks |= attackedByUs & moves; - attackedByUs |= moves; - ptAttacks |= moves; - } -} - -// Refactored getPtPtThreatsFeat with a lambda to process each threat type. -template -static inline PScore getPtPtThreatsFeat(Position &pos, - const BitBoard (&weakPieces)[2], - BitBoard (&pawnAttacks)[2], - BitBoard (&ptAttacks)[2][4], - S8* features) -{ - constexpr int them = !us; - auto &occ = pos.occupancies; - PScore score = S(0, 0); - - // Lambda to process threats and update feature values. - auto processFeatThreats = [&](BitBoard threats, int offset) { - while (threats) { - const Square sq = popLsb(threats); - Piece piece = pos.pieceOn(sq) - 6 * them; - if (piece == K) - continue; - bool weakTarget = (weakPieces[them] & squareBB(sq)) != 0; - features[offset + 5 * (!weakTarget) + piece] += (us == WHITE ? 1 : -1); - } - }; - - processFeatThreats(pawnAttacks[us] & occ[them], 0); - processFeatThreats(ptAttacks[us][N - 1] & occ[them], 10); - processFeatThreats(ptAttacks[us][B - 1] & occ[them], 20); - processFeatThreats(ptAttacks[us][R - 1] & occ[them], 30); - processFeatThreats(ptAttacks[us][Q - 1] & occ[them], 40); - - return score; -} - -template -static inline PScore evalPtPtThreats(Position &pos, - const BitBoard (&weakPieces)[2], - BitBoard (&pawnAttacks)[2], - BitBoard (&ptAttacks)[2][4]) -{ - constexpr int them = !us; - auto &occ = pos.occupancies; - PScore score = S(0, 0); - - // This lambda takes a threat bitboard and a threat evaluation table. - // It uses the table internally to add the proper bonus to score. - auto processEvalThreats = [&](BitBoard threats, const auto &threatTable) { - while (threats) { - const Square sq = popLsb(threats); - Piece piece = pos.pieceOn(sq) - 6 * them; - if (piece == K) - continue; - // Uses the passed table to compute the bonus. - score += threatTable[!(weakPieces[them] & squareBB(sq))][piece]; - } - }; - - processEvalThreats(pawnAttacks[us] & occ[them], PAWNTHREAT); - processEvalThreats(ptAttacks[us][N - 1] & occ[them], KNIGHTTHREAT); - processEvalThreats(ptAttacks[us][B - 1] & occ[them], BISHOPTHREAT); - processEvalThreats(ptAttacks[us][R - 1] & occ[them], ROOKTHREAT); - processEvalThreats(ptAttacks[us][Q - 1] & occ[them], QUEENTHREAT); - - return score; -} - - -static inline BitBoard filesFromBB(BitBoard bb){ - bb |= bb >> 8 | bb << 8; - bb |= bb >> 16 | bb << 16; - bb |= bb >> 32 | bb << 32; - return bb; -} - -template -static inline BitBoard advancePathMasked(BitBoard bb, BitBoard mask){ - if constexpr (side == WHITE){ - bb |= (bb >> 8) & mask; - bb |= (bb >> 16) & mask; - bb |= (bb >> 32) & mask; - } - else { - bb |= (bb << 8) & mask; - bb |= (bb << 16) & mask; - bb |= (bb << 32) & mask; - } - return bb; -} - -template -static inline BitBoard pawnSpanPawns(BitBoard movers, BitBoard blockers){ - if constexpr (side == WHITE){ - return makePawnAttacks(advancePathMasked(movers, ~blockers)) & ~blockers; - } - else { - return makePawnAttacks(advancePathMasked(movers, ~blockers)) & ~blockers; - } -} - -// A helper structure to bundle the evaluation results for one side. -struct PawnStructureResult { - PScore structureScore; // The sum of structure bonuses/penalties (cacheable). - PScore extraScore; // The extra passed pawn advance bonus (non-cacheable). - BitBoard passers; // The bitboard of candidate passed pawns. - S32 passedCount; // The number of candidate passed pawns. -}; - -// Template function to evaluate pawn structure for a single side. -template -PawnStructureResult pawnStructureEval( - const BitBoard (&bb)[12], - const BitBoard (&doubledPawns)[2], - const BitBoard (&pawnFiles)[2], - const BitBoard (&protectedPawns)[2], - const BitBoard (&pawnBlockage)[2], - const BitBoard (&occ)[3], - const BitBoard (&attackedBy)[2], - const BitBoard (multiAttacks)[2], - const BitBoard (defendedByPawn)[2]) -{ - constexpr auto them = 1 - us; - PawnStructureResult result = { PScore(0,0), PScore(0,0), 0ULL, 0 }; - // Use the appropriate pawn index: for WHITE we use P, for BLACK we use p. - constexpr int ourPawnsIndex = (us == WHITE ? P : p); - constexpr int theirPawnsIndex = (us == WHITE ? p : P); - constexpr auto pushUp = us == WHITE ? north : south; - constexpr auto ahead = us == WHITE ? squaresAhead : squaresBehind; - BitBoard pieces = bb[ourPawnsIndex]; - - // Compute "block" used for passed pawn bonus. - // (For the side being evaluated, the block mask combines the overall occupancy with the enemy pawns’ defensive gaps.) - BitBoard block = occ[BOTH] | - (~defendedByPawn[us] & ((~attackedBy[us] & attackedBy[them]) | (multiAttacks[them]))); - PScore score = S(0,0); - PScore extraScore = S(0,0); - while (pieces) { - Square sq = popLsb(pieces); - BitBoard sqb = squareBB(sq); - // For white, rank runs from 0 (promotion) to 7; for black the opposite. - U8 rank = (us == WHITE ? 7 - rankOf(sq) : rankOf(sq)); - - // Common pawn evaluation flags: - bool doubled = (doubledPawns[us] & sqb) != 0; - bool isolated = !(isolatedPawnMask[sq] & bb[ourPawnsIndex]); - bool pawnOpposed = !(pawnFiles[them] & sqb); - bool supported = (protectedPawns[us] & sqb) != 0; - bool advancable = pawnBlockage[us] & pushUp(sqb); - S8 phal = popcount(phalanx[sq] & bb[ourPawnsIndex]); - // Fully passsed pawn check - const BitBoard stoppers = passedPawnMask[us][sq] & bb[theirPawnsIndex]; - // Candidate passed logic - const BitBoard levers = makePawnAttacks(sqb) & bb[theirPawnsIndex]; - const BitBoard leverPushes = pushUp(makePawnAttacks(sqb)) & bb[theirPawnsIndex]; - S8 supportCount = popcount(makePawnAttacks(sqb) & bb[ourPawnsIndex]); - const bool candidate = (stoppers == (levers | leverPushes)) // No extra pawns behind the blockade - && !(popcount(levers) - supportCount > 1) // No levers outnumbering our support pawns - && !(popcount(leverPushes) - phal > 0) // No lever pushes outnumbering our phalanx support - && !(popcount(levers) && popcount(leverPushes)); // No lever AND lever pushes (both pushing and not pushing the pawn gets it captured) - // Backward pawn test. - bool backward = !( (backwardPawnMask[us][sq] & bb[ourPawnsIndex]) || advancable ); - - // For white, structure penalties are subtracted and bonuses added. - if (isolated) { - if (doubled && pawnOpposed) - score += DOUBLEISOLATEDPEN; - else - score += ISOLATEDPEN; - } - else if (backward) { - score += BACKWARDPEN; - } - - if (doubled && !supported) - score += DOUBLEDPEN; - else if (supported && phal) { - score += SUPPORTEDPHALANX; - score += R_SUPPORTEDPHALANX * (rank - 2); - } - else if (advancable && phal) { - score += ADVANCABLEPHALANX; - score += R_ADVANCABLEPHALANX * (rank - 2); - } - // Only consider most advanced pawn in a file - if (!(ahead(sq) & bb[ourPawnsIndex])){ - // Fully passed pawn - if (!stoppers) { - score += passedRankBonus[supported][rank]; - result.passedCount++; - result.passers |= sqb; - // The passed–pawn path bonus. - extraScore += PASSEDPATHBONUS * popcount(advancePathMasked(sqb, ~block)); - } - // Candidate passed pawn - else if (candidate){ - score += candidateRankBonus[supported][rank]; - } - } - } - result.structureScore += us == WHITE ? score : -score; - result.extraScore += us == WHITE ? extraScore : -extraScore; - return result; -} - -// The overall pawn evaluation function. -inline PScore pawnEval(const HashKey hashKey, - const BitBoard (&bb)[12], - const BitBoard (&doubledPawns)[2], - const BitBoard (&pawnFiles)[2], - const BitBoard (&protectedPawns)[2], - const BitBoard (&pawnBlockage)[2], - const BitBoard (&occ)[3], - const BitBoard (&attackedBy)[2], - const BitBoard (multiAttacks)[2], - const BitBoard (defendedByPawn)[2], - S32& passedCount) -{ - PawnEvalHashEntry& entry = pawnEvalHash[hashKey & 0x3FFFF]; - PScore score = PScore(0, 0); - - // If the pawn evaluation hash entry is valid, use cached structure score and then recompute the non-cacheable passed–pawn bonus. - if (entry.hash == hashKey) { - score = entry.score; - // For white passers (cached by storing all passers together; white pawns are in bb[P]). - BitBoard whitePassers = entry.passers & bb[P]; - { - BitBoard block = occ[BOTH] | (~defendedByPawn[WHITE] & ((~attackedBy[WHITE] & attackedBy[BLACK]) | (multiAttacks[BLACK]))); - while (whitePassers) { - Square sq = popLsb(whitePassers); - BitBoard sqb = squareBB(sq); - score += PASSEDPATHBONUS * popcount(advancePathMasked(sqb, ~block)); - } - } - // For black passers. - BitBoard blackPassers = entry.passers & bb[p]; - { - BitBoard block = occ[BOTH] | (~defendedByPawn[BLACK] & ((~attackedBy[BLACK] & attackedBy[WHITE]) | (multiAttacks[WHITE]))); - while (blackPassers) { - Square sq = popLsb(blackPassers); - BitBoard sqb = squareBB(sq); - score -= PASSEDPATHBONUS * popcount(advancePathMasked(sqb, ~block)); - } - } - passedCount += popcount(entry.passers); - return score; - } - else { - // Recompute both sides’ pawn structure evaluation. - auto whiteEval = pawnStructureEval(bb, doubledPawns, pawnFiles, protectedPawns, pawnBlockage, occ, attackedBy, multiAttacks, defendedByPawn); - auto blackEval = pawnStructureEval(bb, doubledPawns, pawnFiles, protectedPawns, pawnBlockage, occ, attackedBy, multiAttacks, defendedByPawn); - - passedCount += whiteEval.passedCount + blackEval.passedCount; - // The overall score is the sum of the (cacheable) structure score and the (non-cached) passed–pawn path bonus. - score = whiteEval.structureScore + blackEval.structureScore + whiteEval.extraScore + blackEval.extraScore; - - // Save a new hash entry using only the structure (cacheable) part and - // the union of passed–pawn bitboards (so that on a hash hit we can recalc the extra bonus). - entry.hash = hashKey; - entry.score = whiteEval.structureScore + blackEval.structureScore; - entry.passers = whiteEval.passers | blackEval.passers; - - return score; - } -} - -// Template function to evaluate pawn structure for a single side. -template -void extractPawnStructureFeats( - const BitBoard (&bb)[12], - const BitBoard (&doubledPawns)[2], - const BitBoard (&pawnFiles)[2], - const BitBoard (&protectedPawns)[2], - const BitBoard (&pawnBlockage)[2], - const BitBoard (&occ)[3], - const BitBoard (&attackedBy)[2], - const BitBoard (multiAttacks)[2], - const BitBoard (defendedByPawn)[2], - S32& passersCount, - S8* features -) -{ - constexpr auto them = 1 - us; - // Use the appropriate pawn index: for WHITE we use P, for BLACK we use p. - constexpr int ourPawnsIndex = (us == WHITE ? P : p); - constexpr int theirPawnsIndex = (us == WHITE ? p : P); - constexpr auto pushUp = us == WHITE ? north : south; - constexpr auto ahead = us == WHITE ? squaresAhead : squaresBehind; - BitBoard pieces = bb[ourPawnsIndex]; - - // Compute "block" used for passed pawn bonus. - // (For the side being evaluated, the block mask combines the overall occupancy with the enemy pawns’ defensive gaps.) - BitBoard block = occ[BOTH] | - (~defendedByPawn[us] & ((~attackedBy[us] & attackedBy[them]) | (multiAttacks[them]))); - while (pieces) { - Square sq = popLsb(pieces); - BitBoard sqb = squareBB(sq); - // For white, rank runs from 0 (promotion) to 7; for black the opposite. - U8 rank = (us == WHITE ? 7 - rankOf(sq) : rankOf(sq)); - - // Common pawn evaluation flags: - bool doubled = (doubledPawns[us] & sqb) != 0; - bool isolated = !(isolatedPawnMask[sq] & bb[ourPawnsIndex]); - bool pawnOpposed = !(pawnFiles[them] & sqb); - bool supported = (protectedPawns[us] & sqb) != 0; - bool advancable = pawnBlockage[us] & pushUp(sqb); - S8 phal = popcount(phalanx[sq] & bb[ourPawnsIndex]); - // Candidate passed logic - const BitBoard levers = makePawnAttacks(sqb) & bb[theirPawnsIndex]; - const BitBoard leverPushes = pushUp(makePawnAttacks(sqb)) & bb[theirPawnsIndex]; - S8 supportCount = popcount(makePawnAttacks(sqb) & bb[ourPawnsIndex]); - const BitBoard stoppers = passedPawnMask[us][sq] & bb[theirPawnsIndex]; - const bool candidate = (stoppers == (levers | leverPushes)) // No extra pawns behind the blockade - && !(popcount(levers) - supportCount > 1) // No levers outnumbering our support pawns - && !(popcount(leverPushes) - phal > 0) // No lever pushes outnumbering our phalanx support - && !(popcount(levers) && popcount(leverPushes)); // No lever AND lever pushes (both pushing and not pushing the pawn gets it captured) - // Backward pawn test. - bool backward = !( (backwardPawnMask[us][sq] & bb[ourPawnsIndex]) || advancable ); - - // For white, structure penalties are subtracted and bonuses added. - if (isolated) { - if (doubled && pawnOpposed) - features[0] += us == WHITE ? 1 : -1; - else - features[1] += us == WHITE ? 1 : -1; - } - else if (backward) { - features[2] += us == WHITE ? 1 : -1; - } - - if (doubled && !supported) - features[3] += us == WHITE ? 1 : -1; - else if (supported && phal) { - features[4] += us == WHITE ? 1 : -1; - features[5] += (us == WHITE ? 1 : -1) * (rank - 2); - } - else if (advancable && phal) { - features[6] += us == WHITE ? 1 : -1; - features[7] += (us == WHITE ? 1 : -1) * (rank - 2); - } - - // Only consider most advanced pawn in a file - if (!(ahead(sq) & bb[ourPawnsIndex])){ - // Fully passed pawn - if (!stoppers) { - features[8+7*supported+rank] += us == WHITE ? 1 : -1; - features[8+7+7] += (us == WHITE ? 1 : -1) * popcount(advancePathMasked(sqb, ~block)); - passersCount += 1; - } - // Candidate passed pawn - else if (candidate){ - features[8+7+7+1+7*supported+rank] += us == WHITE ? 1 : -1; - } - } - } -} - -Score pestoEval(Position *pos){ - auto const& bb = pos->bitboards; - auto const& occ = pos->occupancies; - HashKey pawnHashKey = pos->pawnHashKey ^ enPassantKeysTable[pos->enPassant]; - prefetch(&pawnEvalHash[pawnHashKey & 0x3FFFF]); - // Setup the game phase - S32 gamePhase = gamephaseInc[P] * popcount(bb[P] | bb[p]) + - gamephaseInc[N] * popcount(bb[N] | bb[n]) + - gamephaseInc[B] * popcount(bb[B] | bb[b]) + - gamephaseInc[R] * popcount(bb[R] | bb[r]) + - gamephaseInc[Q] * popcount(bb[Q] | bb[q]) + - gamephaseInc[K] * popcount(bb[K] | bb[k]); - gamePhase = std::min(gamePhase, (S32)24); // If we have a lot of pieces, we don't want to go over 24 - - const Square whiteKing = lsb(bb[K]); - const Square blackKing = lsb(bb[k]); - - // Mobility calculations - - // Pin, mobility and threat calculations - BitBoard attackedBy[2] = { - kingAttacks[whiteKing], - kingAttacks[blackKing] - }; - - BitBoard pawnAttackedSquares[2] = { - 0, - 0 - }; - - BitBoard multiAttacks[2] = { - 0ULL, - 0ULL - }; - - BitBoard doublePawnAttackedSquares[2] = { - 0ULL, - 0ULL - }; - - { - // Left Attacks - BitBoard sidePawnAttacks[2] = { - ((bb[P] & notFile(0)) >> 9), - ((bb[p] & notFile(0)) << 7) - }; - doublePawnAttackedSquares[WHITE] = sidePawnAttacks[WHITE]; - doublePawnAttackedSquares[BLACK] = sidePawnAttacks[BLACK]; - // Update Multi attacks - multiAttacks[WHITE] |= attackedBy[WHITE] & sidePawnAttacks[WHITE]; - multiAttacks[BLACK] |= attackedBy[BLACK] & sidePawnAttacks[BLACK]; - // Update Normal attacks - attackedBy[WHITE] |= sidePawnAttacks[WHITE]; - attackedBy[BLACK] |= sidePawnAttacks[BLACK]; - // Update exclusive pawn attacks - pawnAttackedSquares[WHITE] |= sidePawnAttacks[WHITE]; - pawnAttackedSquares[BLACK] |= sidePawnAttacks[BLACK]; - // Right Attacks - sidePawnAttacks[WHITE] = ((bb[P] & notFile(7)) >> 7); - sidePawnAttacks[BLACK] = ((bb[p] & notFile(7)) << 9); - doublePawnAttackedSquares[WHITE] &= sidePawnAttacks[WHITE]; - doublePawnAttackedSquares[BLACK] &= sidePawnAttacks[BLACK]; - // Update multi attacks - multiAttacks[WHITE] |= attackedBy[WHITE] & sidePawnAttacks[WHITE]; - multiAttacks[BLACK] |= attackedBy[BLACK] & sidePawnAttacks[BLACK]; - // Update Normal attacks - attackedBy[WHITE] |= sidePawnAttacks[WHITE]; - attackedBy[BLACK] |= sidePawnAttacks[BLACK]; - // Update exclusive pawn attacks - pawnAttackedSquares[WHITE] |= sidePawnAttacks[WHITE]; - pawnAttackedSquares[BLACK] |= sidePawnAttacks[BLACK]; - } - - // Pinned mask - BitBoard RQmask[2] = { - bb[R] | bb[Q], - bb[r] | bb[q] - }; - BitBoard BQmask[2] = { - bb[B] | bb[Q], - bb[b] | bb[q] - }; - BitBoard pinned[2] = { - getPinnedPieces(occ[BOTH], occ[WHITE], whiteKing, RQmask[BLACK], BQmask[BLACK]), - getPinnedPieces(occ[BOTH], occ[BLACK], blackKing, RQmask[WHITE], BQmask[WHITE]) - }; - - const BitBoard blockedPawns[2] = { - bb[P] & (occ[BOTH] >> 8), - bb[p] & (occ[BOTH] << 8) - }; - - BitBoard underDevelopedPawns[2] = { - bb[P] & (ranks(6) | ranks(5)), - bb[p] & (ranks(1) | ranks(2)) - }; - - const BitBoard mobilityArea[2] = { - // Mobility area. - // Squares in the mobility area are: - // 1. Free of our pieces - // 2. Not defended by enemy pawns - - // Calculate a negative mask for the mobility area, and then invert it - (blockedPawns[WHITE] | underDevelopedPawns[WHITE] | pawnAttackedSquares[BLACK] | pinned[WHITE] | bb[K] | bb[Q]) ^ 0xFFFFFFFFFFFFFFFF, - (blockedPawns[BLACK] | underDevelopedPawns[BLACK] | pawnAttackedSquares[WHITE] | pinned[BLACK] | bb[k] | bb[q]) ^ 0xFFFFFFFFFFFFFFFF - }; - - // Calculate the mobility scores (index by phase and color) - const BitBoard pawnSpan[2] = { - advancePathMasked(bb[P], ~(bb[p] | pawnAttackedSquares[BLACK])), - advancePathMasked(bb[p], ~(bb[P] | pawnAttackedSquares[WHITE])) - }; - - const BitBoard outpostSquares[2] = { - (ranks(2) | ranks(3) | ranks(4)) & pawnAttackedSquares[WHITE] & ~(makePawnAttacks(pawnSpan[BLACK]) | bb[p]) & notFile(0) & notFile(7), - (ranks(5) | ranks(4) | ranks(3)) & pawnAttackedSquares[BLACK] & ~(makePawnAttacks(pawnSpan[WHITE]) | bb[P]) & notFile(0) & notFile(7) - }; - - const BitBoard nonPawns[2] = { - bb[N] | bb[B] | RQmask[WHITE], - bb[n] | bb[b] | RQmask[BLACK], - }; - - const BitBoard kingRing[2] = { - kingAttacks[whiteKing] & ~doublePawnAttackedSquares[WHITE], - kingAttacks[blackKing] & ~doublePawnAttackedSquares[BLACK] - }; - - const BitBoard kingOuter[2] = { - fiveSquare[whiteKing] & ~doublePawnAttackedSquares[WHITE], - fiveSquare[blackKing] & ~doublePawnAttackedSquares[BLACK] - }; - BitBoard kingCheckers[2][4] = { - { - knightAttacks[whiteKing], - getBishopAttack(whiteKing, occ[BOTH]), - getRookAttack(whiteKing, occ[BOTH]), - 0 - }, - { - knightAttacks[blackKing], - getBishopAttack(blackKing, occ[BOTH]), - getRookAttack(blackKing, occ[BOTH]), - 0 - } - }; - kingCheckers[WHITE][Q-1] = kingCheckers[WHITE][B-1] | kingCheckers[WHITE][R-1]; - kingCheckers[BLACK][Q-1] = kingCheckers[BLACK][B-1] | kingCheckers[BLACK][R-1]; - - BitBoard ptAttacks[2][4] = { {0} }; - - PScore innerAttacks[2] = {PScore(0,0), PScore(0,0)}; - PScore outerAttacks[2] = {PScore(0,0), PScore(0,0)}; - - PScore score = PScore(0,0); - - // std::cout << "PSQT scores are :\t"<<-score.mg()<<"\t"<<-score.eg()<(bb+6, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], score, attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][N-1], blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK], outerAttacks[BLACK]); - mobility(bb+6, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], score, attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][B-1], blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK], outerAttacks[BLACK]); - mobility(bb+6, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], score, attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][R-1], blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK], outerAttacks[BLACK]); - mobility(bb+6, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], score, attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][Q-1], blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK], outerAttacks[BLACK]); - - // Flip - score = -score; - - // White mobility - mobility(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], score, attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][N-1], whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE], outerAttacks[WHITE]); - mobility(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], score, attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][B-1], whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE], outerAttacks[WHITE]); - mobility(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], score, attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][R-1], whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE], outerAttacks[WHITE]); - mobility(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], score, attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][Q-1], whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE], outerAttacks[WHITE]); - - bool wkhside = fileOf(whiteKing) <= 3; - bool bkhside = fileOf(blackKing) <= 3; - - score += pos->psqtScores[indexColorKingsKingside(WHITE, wkhside == bkhside, wkhside)] + pos->psqtScores[indexColorKingsKingside(BLACK, wkhside == bkhside, bkhside)]; - - // Weak pieces - const BitBoard weakPieces[2] = { - occ[WHITE] & ~pawnAttackedSquares[WHITE] & ((attackedBy[BLACK] & ~attackedBy[WHITE]) | (multiAttacks[BLACK] & ~multiAttacks[WHITE])), - occ[BLACK] & ~pawnAttackedSquares[BLACK] & ((attackedBy[WHITE] & ~attackedBy[BLACK]) | (multiAttacks[WHITE] & ~multiAttacks[BLACK])) - }; - - // Hanging enemies - const BitBoard hanging[2] = { - weakPieces[WHITE] & (~attackedBy[WHITE] | (nonPawns[WHITE] & multiAttacks[BLACK])), - weakPieces[BLACK] & (~attackedBy[BLACK] | (nonPawns[BLACK] & multiAttacks[WHITE])) - }; - - // King Threats (eg op-ness hopefully) (also, cap to 1) - const BitBoard kingThreats[2] = { - weakPieces[BLACK] & kingAttacks[WHITE], - weakPieces[WHITE] & kingAttacks[BLACK] - }; - - // Malus for directly doubled, undefended pawns - const BitBoard protectedPawns[2] = { - bb[P] & pawnAttackedSquares[WHITE], - bb[p] & pawnAttackedSquares[BLACK] - }; - - const BitBoard pawnBlockage[2] = { - bb[p] | bb[P] | pawnAttackedSquares[BLACK], - bb[P] | bb[p] | pawnAttackedSquares[WHITE] - }; - - S32 passedCount = 0; - - BitBoard doubledPawns[2] = { bb[P] & (bb[P] << 8), bb[p] & (bb[p] >> 8) }; - BitBoard pawnFiles[2] = { filesFromBB(bb[P]), filesFromBB(bb[p]) }; - - score += pawnEval(pawnHashKey, bb, doubledPawns, pawnFiles, protectedPawns, pawnBlockage, occ, attackedBy, multiAttacks, pawnAttackedSquares, passedCount); - - // Calculate king safety - // King shield. The inner shield is direcly in front of the king so it should be at least supported by the king itself - BitBoard innerShelters[2] = { - kingShelter[WHITE][whiteKing], - kingShelter[BLACK][blackKing] - }; - // The outer shield is the squares in front of the inner shield. We only consider supported squares - BitBoard outerShelters[2] = { - north(innerShelters[WHITE]) & pawnAttackedSquares[WHITE], - south(innerShelters[BLACK]) & pawnAttackedSquares[BLACK] - }; - - // Get pawns - innerShelters[WHITE] &= bb[P]; - outerShelters[WHITE] &= bb[P]; - innerShelters[BLACK] &= bb[p]; - outerShelters[BLACK] &= bb[p]; - - // Add the shelter bonus - const Score innerShelterDiff = popcount(innerShelters[WHITE]) - popcount(innerShelters[BLACK]); - const Score outerShelterDiff = popcount(outerShelters[WHITE]) - popcount(outerShelters[BLACK]); - score += INNERSHELTER * innerShelterDiff; - score += OUTERSHELTER * outerShelterDiff; - - // Add bonus for bishop pairs - score += BISHOPPAIR * ((popcount(bb[B])>=2) - (popcount(bb[b])>=2)); - - // Add bonus for rooks on open files - const BitBoard openFiles = ~(pawnFiles[WHITE] | pawnFiles[BLACK]); - const BitBoard semiOpenFor[2] = { - ~pawnFiles[WHITE], - ~pawnFiles[BLACK] - }; - const Score openDiff = popcount(bb[R] & openFiles) - popcount(bb[r] & openFiles); - const Score semiOpenDiff = popcount(bb[R] & semiOpenFor[WHITE]) - popcount(bb[r] & semiOpenFor[BLACK]); - score += ROOKONOPENFILE * openDiff; - score += ROOKONSEMIOPENFILE * semiOpenDiff; - - // Add outpost squares bonus for knights and bishops - const Score extKnightOutpostDiff = popcount(outpostSquares[WHITE] & (files(1) | files(6)) & bb[N]) - popcount(outpostSquares[BLACK] & (files(1) | files(6)) & bb[n]); - score += KNIGHTONEXTOUTPOST * extKnightOutpostDiff; - const Score extBishopOutpostDiff = popcount(outpostSquares[WHITE] & (files(1) | files(6)) & bb[B]) - popcount(outpostSquares[BLACK] & (files(1) | files(6)) & bb[b]); - score += BISHOPONEXTOUTPOST * extBishopOutpostDiff; - const Score intKnightOutpostDiff = popcount(outpostSquares[WHITE] & (notFile(1) & notFile(6)) & bb[N]) - popcount(outpostSquares[BLACK] & (notFile(1) & notFile(6)) & bb[n]); - score += KNIGHTONINTOUTPOST * intKnightOutpostDiff; - const Score intBishopOutpostDiff = popcount(outpostSquares[WHITE] & (notFile(1) & notFile(6)) & bb[B]) - popcount(outpostSquares[BLACK] & (notFile(1) & notFile(6)) & bb[b]); - score += BISHOPONINTOUTPOST * intBishopOutpostDiff; - - // Add bonus for bishop-pawn concordance - const Score bishopPawnsDiff = - popcount(bb[B] & squaresOfColor[WHITE]) * popcount(squaresOfColor[WHITE] & bb[P]) * (popcount(blockedPawns[WHITE] & centralFiles) + !(pawnAttackedSquares[WHITE] & squaresOfColor[WHITE] & bb[B])) - - popcount(bb[b] & squaresOfColor[WHITE]) * popcount(squaresOfColor[WHITE] & bb[p]) * (popcount(blockedPawns[BLACK] & centralFiles) + !(pawnAttackedSquares[BLACK] & squaresOfColor[WHITE] & bb[b])) + - popcount(bb[B] & squaresOfColor[BLACK]) * popcount(squaresOfColor[BLACK] & bb[P]) * (popcount(blockedPawns[WHITE] & centralFiles) + !(pawnAttackedSquares[WHITE] & squaresOfColor[BLACK] & bb[B])) - - popcount(bb[b] & squaresOfColor[BLACK]) * popcount(squaresOfColor[BLACK] & bb[p]) * (popcount(blockedPawns[BLACK] & centralFiles) + !(pawnAttackedSquares[BLACK] & squaresOfColor[BLACK] & bb[b])) ; - - score += BISHOPPAWNS * bishopPawnsDiff; - - // Threats - const BitBoard threatSafePawns[2] = { - makePawnAttacks(bb[P] & (attackedBy[WHITE] | ~attackedBy[BLACK])) & nonPawns[BLACK], - makePawnAttacks(bb[p] & (attackedBy[BLACK] | ~attackedBy[WHITE])) & nonPawns[WHITE], - }; - - BitBoard pushes[2] = { - north(bb[P]) & ~(occ[BOTH] | pawnAttackedSquares[BLACK]), - south(bb[p]) & ~(occ[BOTH] | pawnAttackedSquares[WHITE]), - }; - pushes[WHITE] |= north(pushes[WHITE] & ranks(5)) & ~(occ[BOTH] | pawnAttackedSquares[BLACK]); - pushes[BLACK] |= south(pushes[BLACK] & ranks(2)) & ~(occ[BOTH] | pawnAttackedSquares[WHITE]); - - const BitBoard threatPawnPush[2] = { - makePawnAttacks(pushes[WHITE] & (attackedBy[WHITE] | ~attackedBy[BLACK])) & nonPawns[BLACK], - makePawnAttacks(pushes[BLACK] & (attackedBy[BLACK] | ~attackedBy[WHITE])) & nonPawns[WHITE], - }; - - const Score safePawnThreatDiff = popcount(threatSafePawns[WHITE]) - popcount(threatSafePawns[BLACK]); - const Score pawnPushThreatDiff = popcount(threatPawnPush[WHITE]) - popcount(threatPawnPush[BLACK]); - - score += THREATSAFEPAWN * safePawnThreatDiff; - score += THREATPAWNPUSH * pawnPushThreatDiff; - - const Score pawnHangingDiff = popcount(hanging[WHITE] & bb[P]) - popcount(hanging[BLACK] & bb[p]); - const Score nonPawnHangingDiff = popcount(hanging[WHITE] & nonPawns[WHITE]) - popcount(hanging[BLACK] & nonPawns[BLACK]); - score += PAWNHANGING * pawnHangingDiff; - score += NONPAWNHANGING * nonPawnHangingDiff; - - score += evalPtPtThreats(*pos, weakPieces, pawnAttackedSquares, ptAttacks) - evalPtPtThreats(*pos, weakPieces, pawnAttackedSquares, ptAttacks); - - const Score kingThreatsDiff = (!!kingThreats[WHITE]) - (!!kingThreats[BLACK]); - score += KINGTHREAT * kingThreatsDiff; - - // Queen infiltration - const Score queenInfiltrationDiff = popcount(~pawnSpan[BLACK] & (ranks(0) | ranks(1) | ranks(2) | ranks(3)) & bb[Q]) - popcount(~pawnSpan[WHITE] & (ranks(7) | ranks(6) | ranks(5) | ranks(4)) & bb[q]); - score += QUEENINFILTRATION * queenInfiltrationDiff; - - // Latent invasions - - const Score invasionsSquaresDiff = popcount( - (ranks(0) | ranks(1) | ranks(2) | ranks(3)) - & ~pawnSpan[BLACK] - & ~makePawnAttacks(pawnSpan[BLACK]) - & multiAttacks[WHITE] - & ~attackedBy[BLACK] - & ~doublePawnAttackedSquares[WHITE] - ) - popcount( - (ranks(7) | ranks(6) | ranks(5) | ranks(4)) - & ~pawnSpan[WHITE] - & ~makePawnAttacks(pawnSpan[WHITE]) - & multiAttacks[BLACK] - & ~attackedBy[WHITE] - & ~doublePawnAttackedSquares[BLACK] - ); - score += INVASIONSQUARES * invasionsSquaresDiff; - - // Square restriction - const Score restrictedSquaresDiff = popcount(multiAttacks[WHITE] & attackedBy[BLACK] & ~multiAttacks[BLACK]) - popcount(multiAttacks[BLACK] & attackedBy[WHITE] & ~multiAttacks[WHITE]); - score += RESTRICTEDSQUARES * restrictedSquaresDiff; - - // Calculate safe checks - const BitBoard weakSquares[2] = { - attackedBy[BLACK] & (~attackedBy[WHITE] | ((kingAttacks[whiteKing] | ptAttacks[WHITE][Q-1]) & ~multiAttacks[WHITE])), - attackedBy[WHITE] & (~attackedBy[BLACK] | ((kingAttacks[blackKing] | ptAttacks[BLACK][Q-1]) & ~multiAttacks[BLACK])), - }; - - const BitBoard checks[2][4] = { - { - ptAttacks[WHITE][N-1] & kingCheckers[BLACK][N-1], - ptAttacks[WHITE][B-1] & kingCheckers[BLACK][B-1], - ptAttacks[WHITE][R-1] & kingCheckers[BLACK][R-1], - ptAttacks[WHITE][Q-1] & kingCheckers[BLACK][Q-1], - }, - { - ptAttacks[BLACK][N-1] & kingCheckers[WHITE][N-1], - ptAttacks[BLACK][B-1] & kingCheckers[WHITE][B-1], - ptAttacks[BLACK][R-1] & kingCheckers[WHITE][R-1], - ptAttacks[BLACK][Q-1] & kingCheckers[WHITE][Q-1], - } - }; - - BitBoard safeChecks[2][4] = { - { - checks[WHITE][N-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - checks[WHITE][B-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - checks[WHITE][R-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - checks[WHITE][Q-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - }, - { - checks[BLACK][N-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - checks[BLACK][B-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - checks[BLACK][R-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - checks[BLACK][Q-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - } - }; - - safeChecks[WHITE][B-1] &= ~safeChecks[WHITE][Q-1]; - safeChecks[BLACK][B-1] &= ~safeChecks[BLACK][Q-1]; - - safeChecks[WHITE][Q-1] &= ~safeChecks[WHITE][R-1]; - safeChecks[BLACK][Q-1] &= ~safeChecks[BLACK][R-1]; - - // Add kingDanger index eval - // Calcuate danger score - innerAttacks[WHITE] += PAWNATTACKINNERRING * popcount(pawnAttackedSquares[WHITE] & kingRing[BLACK]); - outerAttacks[WHITE] += PAWNATTACKOUTERRING * popcount(pawnAttackedSquares[WHITE] & kingOuter[BLACK]); - innerAttacks[BLACK] += PAWNATTACKINNERRING * popcount(pawnAttackedSquares[BLACK] & kingRing[WHITE]); - outerAttacks[BLACK] += PAWNATTACKOUTERRING * popcount(pawnAttackedSquares[BLACK] & kingOuter[WHITE]); - - PScore dangerIndex[2] = { - innerAttacks[WHITE] + outerAttacks[WHITE], - innerAttacks[BLACK] + outerAttacks[BLACK] - }; - - dangerIndex[WHITE] += NOQUEENDANGER * (!bb[Q]); - dangerIndex[BLACK] += NOQUEENDANGER * (!bb[q]); - - dangerIndex[WHITE] += PINNEDSHELTERDANGER * popcount(pinned[BLACK] & innerShelters[BLACK]); - dangerIndex[BLACK] += PINNEDSHELTERDANGER * popcount(pinned[WHITE] & innerShelters[WHITE]); - - // Flank attacks - dangerIndex[WHITE] += FLANKATTACKS[0] * popcount(attackedBy[WHITE] & kingFlank[BLACK][fileOf(blackKing)]) - + FLANKATTACKS[1] * popcount(multiAttacks[WHITE] & kingFlank[BLACK][fileOf(blackKing)]) - + FLANKDEFENSES[0] * popcount(attackedBy[BLACK] & kingFlank[BLACK][fileOf(blackKing)]) - + FLANKDEFENSES[1] * popcount(multiAttacks[BLACK] & kingFlank[BLACK][fileOf(blackKing)]); - - // Flank attacks - dangerIndex[BLACK] += FLANKATTACKS[0] * popcount(attackedBy[BLACK] & kingFlank[WHITE][fileOf(whiteKing)]) - + FLANKATTACKS[1] * popcount(multiAttacks[BLACK] & kingFlank[WHITE][fileOf(whiteKing)]) - + FLANKDEFENSES[0] * popcount(attackedBy[WHITE] & kingFlank[WHITE][fileOf(whiteKing)]) - + FLANKDEFENSES[1] * popcount(multiAttacks[WHITE] & kingFlank[WHITE][fileOf(whiteKing)]); - - // Safe checks - dangerIndex[WHITE] += SAFECHECK[N-1] * popcount(safeChecks[WHITE][N-1]); - dangerIndex[WHITE] += SAFECHECK[B-1] * popcount(safeChecks[WHITE][B-1]); - dangerIndex[WHITE] += SAFECHECK[R-1] * popcount(safeChecks[WHITE][R-1]); - dangerIndex[WHITE] += SAFECHECK[Q-1] * popcount(safeChecks[WHITE][Q-1]); - dangerIndex[BLACK] += SAFECHECK[N-1] * popcount(safeChecks[BLACK][N-1]); - dangerIndex[BLACK] += SAFECHECK[B-1] * popcount(safeChecks[BLACK][B-1]); - dangerIndex[BLACK] += SAFECHECK[R-1] * popcount(safeChecks[BLACK][R-1]); - dangerIndex[BLACK] += SAFECHECK[Q-1] * popcount(safeChecks[BLACK][Q-1]); - - // Ring weakness attacks - dangerIndex[WHITE] += INNERWEAKNESS * popcount(kingRing[BLACK] & weakSquares[BLACK]); - dangerIndex[WHITE] += OUTERWEAKNESS * popcount(outerRing[BLACK] & weakSquares[BLACK]); - dangerIndex[BLACK] += INNERWEAKNESS * popcount(kingRing[WHITE] & weakSquares[WHITE]); - dangerIndex[BLACK] += OUTERWEAKNESS * popcount(outerRing[WHITE] & weakSquares[WHITE]); - - // All checks - dangerIndex[WHITE] += ALLCHECKS[N-1] * popcount(checks[WHITE][N-1]); - dangerIndex[WHITE] += ALLCHECKS[B-1] * popcount(checks[WHITE][B-1]); - dangerIndex[WHITE] += ALLCHECKS[R-1] * popcount(checks[WHITE][R-1]); - dangerIndex[WHITE] += ALLCHECKS[Q-1] * popcount(checks[WHITE][Q-1]); - dangerIndex[BLACK] += ALLCHECKS[N-1] * popcount(checks[BLACK][N-1]); - dangerIndex[BLACK] += ALLCHECKS[B-1] * popcount(checks[BLACK][B-1]); - dangerIndex[BLACK] += ALLCHECKS[R-1] * popcount(checks[BLACK][R-1]); - dangerIndex[BLACK] += ALLCHECKS[Q-1] * popcount(checks[BLACK][Q-1]); - - dangerIndex[WHITE] += SAFETYINNERSHELTER * popcount(innerShelters[BLACK]); - dangerIndex[WHITE] += SAFETYOUTERSHELTER * popcount(outerShelters[BLACK]); - dangerIndex[BLACK] += SAFETYINNERSHELTER * popcount(innerShelters[WHITE]); - dangerIndex[BLACK] += SAFETYOUTERSHELTER * popcount(outerShelters[WHITE]); - const S32 sign = 1 - 2 * pos->side; - dangerIndex[pos->side] += KSTEMPO; - - //const PScore dampenWhite = PScore(dangerIndex[WHITE].mg() * DAMPEN.mg() / RESOLUTION, dangerIndex[WHITE].eg() * DAMPEN.eg() / RESOLUTION); - //const PScore dampenBlack = PScore(dangerIndex[BLACK].mg() * DAMPEN.mg() / RESOLUTION, dangerIndex[BLACK].eg() * DAMPEN.eg() / RESOLUTION); - - //dangerIndex[WHITE] = dangerIndex[WHITE] - dampenBlack; - //dangerIndex[BLACK] = dangerIndex[BLACK] - dampenWhite; - - const S32 mgWhiteDanger = getKingSafetyMg(dangerIndex[WHITE].mg()); - const S32 egWhiteDanger = getKingSafetyEg(dangerIndex[WHITE].eg()); - const S32 mgBlackDanger = getKingSafetyMg(dangerIndex[BLACK].mg()); - const S32 egBlackDanger = getKingSafetyEg(dangerIndex[BLACK].eg()); - - const PScore safety = PScore(mgWhiteDanger - mgBlackDanger, egWhiteDanger - egBlackDanger); - score += safety; - - // Calculate mg and eg scores - score += TEMPO * sign; - - S32 mgScore = score.mg(); - S32 egScore = score.eg(); - - // Complexity adjustment, so we avoid going into drawish barely better endgames - const S32 outflanking = std::abs(fileOf(whiteKing)- fileOf(blackKing)) - std::abs(rankOf(whiteKing)- rankOf(blackKing)); - const S32 blockedPairs = popcount(north(bb[P]) & bb[p]) * 2; - const S32 pawnTension = popcount(pawnAttackedSquares[WHITE] & bb[p]) + popcount(pawnAttackedSquares[BLACK] & bb[P]); - const BitBoard pawns = bb[P] | bb[p]; - const bool pawnsOnBothFlanks = (boardSide[0] & pawns) && (boardSide[1] & pawns); - const bool almostUnwinnable = outflanking < 0 && !pawnsOnBothFlanks; - const bool infiltration = rankOf(whiteKing) <= 3 || rankOf(blackKing) >= 4; - const Score complexity = (COMPLEXITYPASSERS * passedCount - + COMPLEXITYPAWNS * popcount(pawns) - + COMPLEXITYBLOCKEDPAIRS * blockedPairs - + COMPLEXITYPAWNTENSION * pawnTension - + COMPLEXITYOUTFLANKING * outflanking - + COMPLEXITYINFILTRATION * infiltration - + COMPLEXITYPAWNBOTHFLANKS * pawnsOnBothFlanks - + COMPLEXITYPAWNENDING * !(nonPawns[WHITE] | nonPawns[BLACK]) - + COMPLEXITYALMOSTUNWINNABLE * almostUnwinnable - + COMPLEXITYBIAS) / 100; - - const Score v = ((egScore > 0) - (egScore < 0)) * std::max(complexity, Score(-std::abs(egScore))); - egScore += v; - - return Score( - sign * - ( - mgScore * gamePhase + - egScore * (24 - gamePhase) - ) / 24 - ); -} - -std::vector getCurrentEvalWeights(){ - std::vector weights; - // Add the material weights - for (Piece piece = P; piece <= Q; piece++){ - weights.push_back(materialValues[piece].mg()); - } - // PSQT weights handled later bc of king bucket - // Add the mobility weights - for (U8 mobcount = 0; mobcount < 9; mobcount++){ - weights.push_back(knightMob[mobcount].mg()); - } - for (U8 mobcount = 0; mobcount < 14; mobcount++){ - weights.push_back(bishopMob[mobcount].mg()); - } - for (U8 mobcount = 0; mobcount < 15; mobcount++){ - weights.push_back(rookMob[mobcount].mg()); - } - for (U8 mobcount = 0; mobcount < 28; mobcount++){ - weights.push_back(queenMob[mobcount].mg()); - } - // Add the pawn evaluation weights - weights.push_back(DOUBLEISOLATEDPEN.mg()); - weights.push_back(ISOLATEDPEN.mg()); - weights.push_back(BACKWARDPEN.mg()); - weights.push_back(DOUBLEDPEN.mg()); - weights.push_back(SUPPORTEDPHALANX.mg()); - weights.push_back(R_SUPPORTEDPHALANX.mg()); - weights.push_back(ADVANCABLEPHALANX.mg()); - weights.push_back(R_ADVANCABLEPHALANX.mg()); - // Add the passed pawn bonus list - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(passedRankBonus[0][rank].mg()); - } - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(passedRankBonus[1][rank].mg()); - } - weights.push_back(PASSEDPATHBONUS.mg()); - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(candidateRankBonus[0][rank].mg()); - } - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(candidateRankBonus[1][rank].mg()); - } - - // Add the shelter weights - weights.push_back(INNERSHELTER.mg()); - weights.push_back(OUTERSHELTER.mg()); - - // Add the bishop pair bonus - weights.push_back(BISHOPPAIR.mg()); - - // Add the rook and queen on open file bonus - weights.push_back(ROOKONOPENFILE.mg()); - weights.push_back(ROOKONSEMIOPENFILE.mg()); - - // Now, outpost - weights.push_back(KNIGHTONEXTOUTPOST.mg()); - weights.push_back(BISHOPONEXTOUTPOST.mg()); - weights.push_back(KNIGHTONINTOUTPOST.mg()); - weights.push_back(BISHOPONINTOUTPOST.mg()); - - // Now, king protector - weights.push_back(KNIGHTPROTECTOR.mg()); - weights.push_back(BISHOPPROTECTOR.mg()); - - // Now, bishop pawns - weights.push_back(BISHOPPAWNS.mg()); - - // Now, threats - weights.push_back(THREATSAFEPAWN.mg()); - weights.push_back(THREATPAWNPUSH.mg()); - weights.push_back(PAWNHANGING.mg()); - weights.push_back(NONPAWNHANGING.mg()); - - for (auto t : {PAWNTHREAT, KNIGHTTHREAT, BISHOPTHREAT, ROOKTHREAT, QUEENTHREAT}){ - for (int def : {0, 1}){ - for (Piece target : {P, N, B, R, Q}){ - weights.push_back(t[def][target].mg()); - } - } - } - - weights.push_back(KINGTHREAT.mg()); - weights.push_back(QUEENINFILTRATION.mg()); - weights.push_back(INVASIONSQUARES.mg()); - weights.push_back(RESTRICTEDSQUARES.mg()); - - // Add the tempo bonus - weights.push_back(TEMPO.mg()); - - // Now, EG - // Add the material weights - for (Piece piece = P; piece <= Q; piece++){ - weights.push_back(materialValues[piece].eg()); - } - // Same thing abt PSQTs - // Add the mobility weights - for (U8 mobcount = 0; mobcount < 9; mobcount++){ - weights.push_back(knightMob[mobcount].eg()); - } - for (U8 mobcount = 0; mobcount < 14; mobcount++){ - weights.push_back(bishopMob[mobcount].eg()); - } - for (U8 mobcount = 0; mobcount < 15; mobcount++){ - weights.push_back(rookMob[mobcount].eg()); - } - for (U8 mobcount = 0; mobcount < 28; mobcount++){ - weights.push_back(queenMob[mobcount].eg()); - } - // Add the pawn evaluation weights - weights.push_back(DOUBLEISOLATEDPEN.eg()); - weights.push_back(ISOLATEDPEN.eg()); - weights.push_back(BACKWARDPEN.eg()); - weights.push_back(DOUBLEDPEN.eg()); - weights.push_back(SUPPORTEDPHALANX.eg()); - weights.push_back(R_SUPPORTEDPHALANX.eg()); - weights.push_back(ADVANCABLEPHALANX.eg()); - weights.push_back(R_ADVANCABLEPHALANX.eg()); - - // Add the passed pawn bonus list - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(passedRankBonus[0][rank].eg()); - } - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(passedRankBonus[1][rank].eg()); - } - weights.push_back(PASSEDPATHBONUS.eg()); - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(candidateRankBonus[0][rank].eg()); - } - for (U8 rank = 0; rank < 7; rank++){ - weights.push_back(candidateRankBonus[1][rank].eg()); - } - - // Add the shelter weights - weights.push_back(INNERSHELTER.eg()); - weights.push_back(OUTERSHELTER.eg()); - - // Add the bishop pair bonus - weights.push_back(BISHOPPAIR.eg()); - - // Add the rook and queen on open file bonus - weights.push_back(ROOKONOPENFILE.eg()); - weights.push_back(ROOKONSEMIOPENFILE.eg()); - - // Now, outpost - weights.push_back(KNIGHTONEXTOUTPOST.eg()); - weights.push_back(BISHOPONEXTOUTPOST.eg()); - weights.push_back(KNIGHTONINTOUTPOST.eg()); - weights.push_back(BISHOPONINTOUTPOST.eg()); - - // Now, king protector - weights.push_back(KNIGHTPROTECTOR.eg()); - weights.push_back(BISHOPPROTECTOR.eg()); - - // Now, bishop pawns - weights.push_back(BISHOPPAWNS.eg()); - - // Now, threats - weights.push_back(THREATSAFEPAWN.eg()); - weights.push_back(THREATPAWNPUSH.eg()); - weights.push_back(PAWNHANGING.eg()); - weights.push_back(NONPAWNHANGING.eg()); - - for (auto t : {PAWNTHREAT, KNIGHTTHREAT, BISHOPTHREAT, ROOKTHREAT, QUEENTHREAT}){ - for (int def : {0, 1}){ - for (Piece target : {P, N, B, R, Q}){ - weights.push_back(t[def][target].eg()); - } - } - } - - weights.push_back(KINGTHREAT.eg()); - weights.push_back(QUEENINFILTRATION.eg()); - weights.push_back(INVASIONSQUARES.eg()); - weights.push_back(RESTRICTEDSQUARES.eg()); - - // Add the tempo bonus - weights.push_back(TEMPO.eg()); - - return weights; -} - -// Returns the evaluation features tensor -// This will be used to tune the evaluation function -void getEvalFeaturesTensor(Position *pos, S8* tensor){ - - auto const& bb = pos->bitboards; - auto const& occ = pos->occupancies; - auto us = pos->side; - Square whiteKing = lsb(bb[K]); - Square blackKing = lsb(bb[k]); - bool wkhside = fileOf(whiteKing) <= 3; - bool bkhside = fileOf(blackKing) <= 3; - - - // Calculate the game phase - S32 gamePhase = gamephaseInc[P] * popcount(bb[P] | bb[p]) + - gamephaseInc[N] * popcount(bb[N] | bb[n]) + - gamephaseInc[B] * popcount(bb[B] | bb[b]) + - gamephaseInc[R] * popcount(bb[R] | bb[r]) + - gamephaseInc[Q] * popcount(bb[Q] | bb[q]) + - gamephaseInc[K] * popcount(bb[K] | bb[k]); - - gamePhase = std::min(gamePhase, (S32)24); // If we have a lot of pieces, we don't want to go over 24 - // Add the game phase - tensor[0] = gamePhase; - ++tensor; - - // Add the psqt weights. Only add them once, no need to bloat the data. - for (Square square = a8; square < noSquare; square++){ - Piece piece = pos->pieceOn(square); - if (piece == NOPIECE) continue; - Square sq = piece < p ? square : flipSquare(square); - U8 sqx = sq & 7; - sqx = (piece < p) ? - (wkhside ? sqx : 7 - sqx) : - (bkhside ? sqx : 7 - sqx) ; - U8 sqy = sq / 8; - sq = sqx + 8 * sqy; - bool pieceColor = piece >= p; - tensor[64 * (piece % 6) + sq] += (pieceColor ? 0b0100 : 0b0001) << (wkhside == bkhside); - } - tensor += 64 * 6; - - // Add the material weights - for (Piece piece = P; piece <= Q; piece++){ - tensor[piece] = popcount(pos->bitboards[piece]) - popcount(pos->bitboards[piece + 6]); - } - tensor += 5; - - // Pin, mobility and threat calculations - BitBoard attackedBy[2] = { - kingAttacks[whiteKing], - kingAttacks[blackKing] - }; - - BitBoard pawnAttackedSquares[2] = { - 0, - 0 - }; - - - BitBoard multiAttacks[2] = { - 0ULL, - 0ULL - }; - - BitBoard doublePawnAttackedSquares[2] = { - 0ULL, - 0ULL - }; - - { - // Left Attacks - BitBoard sidePawnAttacks[2] = { - ((bb[P] & notFile(0)) >> 9), - ((bb[p] & notFile(0)) << 7) - }; - doublePawnAttackedSquares[WHITE] = sidePawnAttacks[WHITE]; - doublePawnAttackedSquares[BLACK] = sidePawnAttacks[BLACK]; - // Update Multi attacks - multiAttacks[WHITE] |= attackedBy[WHITE] & sidePawnAttacks[WHITE]; - multiAttacks[BLACK] |= attackedBy[BLACK] & sidePawnAttacks[BLACK]; - // Update Normal attacks - attackedBy[WHITE] |= sidePawnAttacks[WHITE]; - attackedBy[BLACK] |= sidePawnAttacks[BLACK]; - // Update exclusive pawn attacks - pawnAttackedSquares[WHITE] |= sidePawnAttacks[WHITE]; - pawnAttackedSquares[BLACK] |= sidePawnAttacks[BLACK]; - // Right Attacks - sidePawnAttacks[WHITE] = ((bb[P] & notFile(7)) >> 7); - sidePawnAttacks[BLACK] = ((bb[p] & notFile(7)) << 9); - doublePawnAttackedSquares[WHITE] &= sidePawnAttacks[WHITE]; - doublePawnAttackedSquares[BLACK] &= sidePawnAttacks[BLACK]; - // Update multi attacks - multiAttacks[WHITE] |= attackedBy[WHITE] & sidePawnAttacks[WHITE]; - multiAttacks[BLACK] |= attackedBy[BLACK] & sidePawnAttacks[BLACK]; - // Update Normal attacks - attackedBy[WHITE] |= sidePawnAttacks[WHITE]; - attackedBy[BLACK] |= sidePawnAttacks[BLACK]; - // Update exclusive pawn attacks - pawnAttackedSquares[WHITE] |= sidePawnAttacks[WHITE]; - pawnAttackedSquares[BLACK] |= sidePawnAttacks[BLACK]; - } - - // Pinned mask - BitBoard RQmask[2] = { - bb[R] | bb[Q], - bb[r] | bb[q] - }; - BitBoard BQmask[2] = { - bb[B] | bb[Q], - bb[b] | bb[q] - }; - BitBoard pinned[2] = { - getPinnedPieces(occ[BOTH], occ[WHITE], whiteKing, RQmask[BLACK], BQmask[BLACK]), - getPinnedPieces(occ[BOTH], occ[BLACK], blackKing, RQmask[WHITE], BQmask[WHITE]) - }; - - BitBoard blockedPawns[2] = { - bb[P] & (occ[BOTH] >> 8), - bb[p] & (occ[BOTH] << 8) - }; - - BitBoard underDevelopedPawns[2] = { - bb[P] & (ranks(6) | ranks(5)), - bb[p] & (ranks(1) | ranks(2)) - }; - - BitBoard mobilityArea[2] = { - // Mobility area. - // Squares in the mobility area are: - // 1. Free of our pieces - // 2. Not defended by enemy pawns - - // Calculate a negative mask for the mobility area, and then invert it - (blockedPawns[WHITE] | underDevelopedPawns[WHITE] | pawnAttackedSquares[BLACK] | pinned[WHITE] | bb[K] | bb[Q]) ^ 0xFFFFFFFFFFFFFFFF, - (blockedPawns[BLACK] | underDevelopedPawns[BLACK] | pawnAttackedSquares[WHITE] | pinned[BLACK] | bb[k] | bb[q]) ^ 0xFFFFFFFFFFFFFFFF - }; - - BitBoard nonPawns[2] = { - bb[N] | bb[B] | bb[R] | bb[Q], - bb[n] | bb[b] | bb[r] | bb[q], - }; - - const BitBoard kingRing[2] = { - kingAttacks[whiteKing] & ~doublePawnAttackedSquares[WHITE], - kingAttacks[blackKing] & ~doublePawnAttackedSquares[BLACK] - }; - - const BitBoard kingOuter[2] = { - fiveSquare[whiteKing] & ~doublePawnAttackedSquares[WHITE], - fiveSquare[blackKing] & ~doublePawnAttackedSquares[BLACK] - }; - - S32 innerAttacks[2][5] = { {0} }; - S32 outerAttacks[2][5] = { {0} }; - S32 kingDist[2] = {0}; - - BitBoard kingCheckers[2][4] = { - { - knightAttacks[whiteKing], - getBishopAttack(whiteKing, occ[BOTH]), - getRookAttack(whiteKing, occ[BOTH]), - 0 - }, - { - knightAttacks[blackKing], - getBishopAttack(blackKing, occ[BOTH]), - getRookAttack(blackKing, occ[BOTH]), - 0 - } - }; - kingCheckers[WHITE][Q-1] = kingCheckers[WHITE][B-1] | kingCheckers[WHITE][R-1]; - kingCheckers[BLACK][Q-1] = kingCheckers[BLACK][B-1] | kingCheckers[BLACK][R-1]; - - BitBoard ptAttacks[2][4] = { {0} }; - - innerAttacks[WHITE][P] = popcount(pawnAttackedSquares[WHITE] & kingRing[BLACK]); - innerAttacks[BLACK][P] = popcount(pawnAttackedSquares[BLACK] & kingRing[WHITE]); - outerAttacks[WHITE][P] = popcount(pawnAttackedSquares[WHITE] & kingOuter[BLACK]); - outerAttacks[BLACK][P] = popcount(pawnAttackedSquares[BLACK] & kingOuter[WHITE]); - - // Calculate the mobility scores (index by phase and color) - getMobilityFeat(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][N-1], tensor, whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE][N], outerAttacks[WHITE][N], kingDist[0]); - getMobilityFeat(bb, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][N-1], tensor, blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK][N], outerAttacks[BLACK][N], kingDist[0]); - tensor += 9; - getMobilityFeat(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][B-1], tensor, whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE][B], outerAttacks[WHITE][B], kingDist[1]); - getMobilityFeat(bb, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][B-1], tensor, blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK][B], outerAttacks[BLACK][B], kingDist[1]); - tensor += 14; - getMobilityFeat(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][R-1], tensor, whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE][R], outerAttacks[WHITE][R], kingDist[0]); - getMobilityFeat(bb, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][R-1], tensor, blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK][R], outerAttacks[BLACK][R], kingDist[0]); - tensor += 15; - getMobilityFeat(bb, occ[BOTH], pinned[WHITE], mobilityArea[WHITE], attackedBy[WHITE], multiAttacks[WHITE], ptAttacks[WHITE][Q-1], tensor, whiteKing, kingRing[BLACK], kingOuter[BLACK], innerAttacks[WHITE][Q], outerAttacks[WHITE][Q], kingDist[0]); - getMobilityFeat(bb, occ[BOTH], pinned[BLACK], mobilityArea[BLACK], attackedBy[BLACK], multiAttacks[BLACK], ptAttacks[BLACK][Q-1], tensor, blackKing, kingRing[WHITE], kingOuter[WHITE], innerAttacks[BLACK][Q], outerAttacks[BLACK][Q], kingDist[0]); - tensor += 28; - - // Weak pieces - BitBoard weakPieces[2] = { - occ[WHITE] & ~pawnAttackedSquares[WHITE] & ((attackedBy[BLACK] & ~attackedBy[WHITE]) | (multiAttacks[BLACK] & ~multiAttacks[WHITE])), - occ[BLACK] & ~pawnAttackedSquares[BLACK] & ((attackedBy[WHITE] & ~attackedBy[BLACK]) | (multiAttacks[WHITE] & ~multiAttacks[BLACK])) - }; - - // Hanging enemies - BitBoard hanging[2] = { - weakPieces[WHITE] & (~attackedBy[WHITE] | (nonPawns[WHITE] & multiAttacks[BLACK])), - weakPieces[BLACK] & (~attackedBy[BLACK] | (nonPawns[BLACK] & multiAttacks[WHITE])) - }; - - // King Threats (eg op-ness hopefully) (also, cap to 1) - BitBoard kingThreats[2] = { - weakPieces[BLACK] & kingAttacks[WHITE], - weakPieces[WHITE] & kingAttacks[BLACK] - }; - - // Add the pawn evaluation weights - // Malus for directly doubled, undefended pawns - BitBoard protectedPawns[2] = { - bb[P] & pawnAttackedSquares[WHITE], - bb[p] & pawnAttackedSquares[BLACK] - }; - - BitBoard pawnBlockage[2] = { - bb[p] | bb[P] | pawnAttackedSquares[BLACK], - bb[P] | bb[p] | pawnAttackedSquares[WHITE] - }; - - S32 passedCount = 0; - - BitBoard doubledPawns[2] = { bb[P] & (bb[P] << 8), bb[p] & (bb[p] >> 8) }; - BitBoard pawnFiles[2] = { filesFromBB(bb[P]), filesFromBB(bb[p]) }; - - extractPawnStructureFeats(bb,doubledPawns,pawnFiles,protectedPawns,pawnBlockage,occ,attackedBy,multiAttacks,pawnAttackedSquares, passedCount, tensor); - extractPawnStructureFeats(bb,doubledPawns,pawnFiles,protectedPawns,pawnBlockage,occ,attackedBy,multiAttacks,pawnAttackedSquares, passedCount, tensor); - - tensor += 8 + 7 + 7 + 1 + 7 + 7; - - // Calculate king safety - // King shield. The inner shield is direcly in front of the king so it should be at least supported by the king itself - BitBoard innerShelters[2] = { - kingShelter[WHITE][whiteKing], - kingShelter[BLACK][blackKing] - }; - // The outer shield is the squares in front of the inner shield. We only consider supported squares - BitBoard outerShelters[2] = { - north(innerShelters[WHITE]) & pawnAttackedSquares[WHITE], - south(innerShelters[BLACK]) & pawnAttackedSquares[BLACK] - }; - - // Get pawns - innerShelters[WHITE] &= bb[P]; - innerShelters[BLACK] &= bb[p]; - outerShelters[WHITE] &= bb[P]; - outerShelters[BLACK] &= bb[p]; - - // Add the shelter bonus - tensor[0] += popcount(innerShelters[WHITE]) - popcount(innerShelters[BLACK]); - tensor[1] += popcount(outerShelters[WHITE]) - popcount(outerShelters[BLACK]); - tensor += 2; - - // Add the bishop pairs - tensor[0] += (popcount(bb[B])>=2) - (popcount(bb[b])>=2); - tensor++; - - // Add the rooks on open files - BitBoard openFiles = ~(pawnFiles[WHITE] | pawnFiles[BLACK]); - BitBoard semiOpenFor[2] = { - ~pawnFiles[WHITE], - ~pawnFiles[BLACK] - }; - tensor[0] += (popcount(bb[R] & openFiles) - popcount(bb[r] & openFiles)); - tensor[1] += (popcount(bb[R] & semiOpenFor[WHITE]) - popcount(bb[r] & semiOpenFor[BLACK])); - tensor += 2; - - // Outpost calculations - BitBoard pawnSpan[2] = { - advancePathMasked(bb[P], ~(bb[p] | pawnAttackedSquares[BLACK])), - advancePathMasked(bb[p], ~(bb[P] | pawnAttackedSquares[WHITE])) - }; - - BitBoard outpostSquares[2] = { - (ranks(2) | ranks(3) | ranks(4)) & pawnAttackedSquares[WHITE] & ~(makePawnAttacks(pawnSpan[BLACK]) | bb[p]) & notFile(0) & notFile(7), - (ranks(5) | ranks(4) | ranks(3)) & pawnAttackedSquares[BLACK] & ~(makePawnAttacks(pawnSpan[WHITE]) | bb[P]) & notFile(0) & notFile(7) - }; - - Score extKnightOutpostDiff = popcount(outpostSquares[WHITE] & (files(1) | files(6)) & bb[N]) - popcount(outpostSquares[BLACK] & (files(1) | files(6)) & bb[n]); - tensor[0] += extKnightOutpostDiff; - Score extBishopOutpostDiff = popcount(outpostSquares[WHITE] & (files(1) | files(6)) & bb[B]) - popcount(outpostSquares[BLACK] & (files(1) | files(6)) & bb[b]); - tensor[1] += extBishopOutpostDiff; - Score intKnightOutpostDiff = popcount(outpostSquares[WHITE] & (notFile(1) & notFile(6)) & bb[N]) - popcount(outpostSquares[BLACK] & (notFile(1) & notFile(6)) & bb[n]); - tensor[2] += intKnightOutpostDiff; - Score intBishopOutpostDiff = popcount(outpostSquares[WHITE] & (notFile(1) & notFile(6)) & bb[B]) - popcount(outpostSquares[BLACK] & (notFile(1) & notFile(6)) & bb[b]); - tensor[3] += intBishopOutpostDiff; - tensor += 4; - - tensor[0] = kingDist[0]; - tensor[1] = kingDist[1]; - tensor += 2; - - // Add bonus for bishop-pawn concordance (technically broken in two same colored bishop cases, but kek) - Score bishopPawnsDiff = - popcount(bb[B] & squaresOfColor[WHITE]) * popcount(squaresOfColor[WHITE] & bb[P]) * (popcount(blockedPawns[WHITE] & centralFiles) + !(pawnAttackedSquares[WHITE] & squaresOfColor[WHITE] & bb[B])) - - popcount(bb[b] & squaresOfColor[WHITE]) * popcount(squaresOfColor[WHITE] & bb[p]) * (popcount(blockedPawns[BLACK] & centralFiles) + !(pawnAttackedSquares[BLACK] & squaresOfColor[WHITE] & bb[b])) + - popcount(bb[B] & squaresOfColor[BLACK]) * popcount(squaresOfColor[BLACK] & bb[P]) * (popcount(blockedPawns[WHITE] & centralFiles) + !(pawnAttackedSquares[WHITE] & squaresOfColor[BLACK] & bb[B])) - - popcount(bb[b] & squaresOfColor[BLACK]) * popcount(squaresOfColor[BLACK] & bb[p]) * (popcount(blockedPawns[BLACK] & centralFiles) + !(pawnAttackedSquares[BLACK] & squaresOfColor[BLACK] & bb[b])) ; - - tensor[0] += bishopPawnsDiff; - - tensor++; - - // Threats - BitBoard threatSafePawns[2] = { - makePawnAttacks(bb[P] & (attackedBy[WHITE] | ~attackedBy[BLACK])) & nonPawns[BLACK], - makePawnAttacks(bb[p] & (attackedBy[BLACK] | ~attackedBy[WHITE])) & nonPawns[WHITE], - }; - - BitBoard pushes[2] = { - north(bb[P]) & ~(occ[BOTH] | pawnAttackedSquares[BLACK]), - south(bb[p]) & ~(occ[BOTH] | pawnAttackedSquares[WHITE]), - }; - pushes[WHITE] |= north(pushes[WHITE] & ranks(5)) & ~(occ[BOTH] | pawnAttackedSquares[BLACK]); - pushes[BLACK] |= south(pushes[BLACK] & ranks(2)) & ~(occ[BOTH] | pawnAttackedSquares[WHITE]); - - BitBoard threatPawnPush[2] = { - makePawnAttacks(pushes[WHITE] & (attackedBy[WHITE] | ~attackedBy[BLACK])) & nonPawns[BLACK], - makePawnAttacks(pushes[BLACK] & (attackedBy[BLACK] | ~attackedBy[WHITE])) & nonPawns[WHITE], - }; - - Score safePawnThreatDiff = popcount(threatSafePawns[WHITE]) - popcount(threatSafePawns[BLACK]); - Score pawnPushThreatDiff = popcount(threatPawnPush[WHITE]) - popcount(threatPawnPush[BLACK]); - - tensor[0] = safePawnThreatDiff; - tensor[1] = pawnPushThreatDiff; - tensor += 2; - - const Score pawnHangingDiff = popcount(hanging[WHITE] & bb[P]) - popcount(hanging[BLACK] & bb[p]); - const Score nonPawnHangingDiff = popcount(hanging[WHITE] & nonPawns[WHITE]) - popcount(hanging[BLACK] & nonPawns[BLACK]); - tensor[0] = pawnHangingDiff; - tensor[1] = nonPawnHangingDiff; - tensor += 2; - - getPtPtThreatsFeat(*pos, weakPieces, pawnAttackedSquares, ptAttacks, tensor); - getPtPtThreatsFeat(*pos, weakPieces, pawnAttackedSquares, ptAttacks, tensor); - - tensor += 50; - - const Score kingThreatsDiff = (!!kingThreats[WHITE]) - (!!kingThreats[BLACK]); - tensor[0] = kingThreatsDiff; - ++tensor; - - // Queen infiltration - const Score queenInfiltrationDiff = popcount(~pawnSpan[BLACK] & (ranks(0) | ranks(1) | ranks(2) | ranks(3)) & bb[Q]) - popcount(~pawnSpan[WHITE] & (ranks(7) | ranks(6) | ranks(5) | ranks(4)) & bb[q]); - tensor[0] = queenInfiltrationDiff; - ++tensor; - - // Latent invasions - const Score invasionsSquaresDiff = popcount( - (ranks(0) | ranks(1) | ranks(2) | ranks(3)) - & ~pawnSpan[BLACK] - & ~makePawnAttacks(pawnSpan[BLACK]) - & multiAttacks[WHITE] - & ~attackedBy[BLACK] - & ~doublePawnAttackedSquares[WHITE] - ) - popcount( - (ranks(7) | ranks(6) | ranks(5) | ranks(4)) - & ~pawnSpan[WHITE] - & ~makePawnAttacks(pawnSpan[WHITE]) - & multiAttacks[BLACK] - & ~attackedBy[WHITE] - & ~doublePawnAttackedSquares[BLACK] - ); - tensor[0] = invasionsSquaresDiff; - ++tensor; - - // Square restriction - const Score restrictedSquaresDiff = popcount(multiAttacks[WHITE] & attackedBy[BLACK] & ~multiAttacks[BLACK]) - popcount(multiAttacks[BLACK] & attackedBy[WHITE] & ~multiAttacks[WHITE]); - tensor[0] = restrictedSquaresDiff; - ++tensor; - - // Add the tempo bonus - tensor[0] += us == WHITE ? 1 : -1; - tensor++; - - // Now, king index eval. - Score noQueenDanger[2] = {!bb[Q], !bb[q]}; - S32 pinnedShelter[2] = {popcount(pinned[BLACK] & innerShelters[BLACK]), popcount(pinned[WHITE] & innerShelters[WHITE])}; - // Calculate safe checks - const BitBoard weakSquares[2] = { - attackedBy[BLACK] & (~attackedBy[WHITE] | ((kingAttacks[whiteKing] | ptAttacks[WHITE][Q-1]) & ~multiAttacks[WHITE])), - attackedBy[WHITE] & (~attackedBy[BLACK] | ((kingAttacks[blackKing] | ptAttacks[BLACK][Q-1]) & ~multiAttacks[BLACK])), - }; - - const BitBoard checks[2][4] = { - { - ptAttacks[WHITE][N-1] & kingCheckers[BLACK][N-1], - ptAttacks[WHITE][B-1] & kingCheckers[BLACK][B-1], - ptAttacks[WHITE][R-1] & kingCheckers[BLACK][R-1], - ptAttacks[WHITE][Q-1] & kingCheckers[BLACK][Q-1], - }, - { - ptAttacks[BLACK][N-1] & kingCheckers[WHITE][N-1], - ptAttacks[BLACK][B-1] & kingCheckers[WHITE][B-1], - ptAttacks[BLACK][R-1] & kingCheckers[WHITE][R-1], - ptAttacks[BLACK][Q-1] & kingCheckers[WHITE][Q-1], - } - }; - - BitBoard safeChecks[2][4] = { - { - checks[WHITE][N-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - checks[WHITE][B-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - checks[WHITE][R-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - checks[WHITE][Q-1] & (~attackedBy[BLACK] | (weakSquares[BLACK] & multiAttacks[WHITE])), - }, - { - checks[BLACK][N-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - checks[BLACK][B-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - checks[BLACK][R-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - checks[BLACK][Q-1] & (~attackedBy[WHITE] | (weakSquares[WHITE] & multiAttacks[BLACK])), - } - }; - - - safeChecks[WHITE][B-1] &= ~safeChecks[WHITE][Q-1]; - safeChecks[BLACK][B-1] &= ~safeChecks[BLACK][Q-1]; - - safeChecks[WHITE][Q-1] &= ~safeChecks[WHITE][R-1]; - safeChecks[BLACK][Q-1] &= ~safeChecks[BLACK][R-1]; - -#define COMPLEXITYFEATURES 9 - - // Complexity adjustment, so we avoid going into drawish barely better endgames - Score outflanking = std::abs(fileOf(whiteKing)- fileOf(blackKing)) - std::abs(rankOf(whiteKing)- rankOf(blackKing)); - Score blockedPairs = popcount(north(bb[P]) & bb[p]) * 2; - Score pawnTension = popcount(pawnAttackedSquares[WHITE] & bb[p]) + popcount(pawnAttackedSquares[BLACK] & bb[P]); - BitBoard pawns = bb[P] | bb[p]; - bool pawnsOnBothFlanks = (boardSide[0] & pawns) && (boardSide[1] & pawns); - bool almostUnwinnable = outflanking < 0 && !pawnsOnBothFlanks; - bool infiltration = rankOf(whiteKing) <= 3 || rankOf(blackKing) >= 4; - - tensor[0] = passedCount; - tensor[1] = popcount(pawns); - tensor[2] = blockedPairs; - tensor[3] = pawnTension; - tensor[4] = outflanking; - tensor[5] = infiltration; - tensor[6] = pawnsOnBothFlanks; - tensor[7] = !(nonPawns[WHITE] | nonPawns[BLACK]); - tensor[8] = almostUnwinnable; - - tensor += 9; - - -#define KINGSAFETYCOLOREDPARAMS 58 - tensor[P] = innerAttacks[WHITE][P]; - tensor[N] = innerAttacks[WHITE][N]; - tensor[B] = innerAttacks[WHITE][B]; - tensor[R] = innerAttacks[WHITE][R]; - tensor[Q] = innerAttacks[WHITE][Q]; - tensor += 5; - tensor[P] = outerAttacks[WHITE][P]; - tensor[N] = outerAttacks[WHITE][N]; - tensor[B] = outerAttacks[WHITE][B]; - tensor[R] = outerAttacks[WHITE][R]; - tensor[Q] = outerAttacks[WHITE][Q]; - tensor += 5; - tensor[0] = noQueenDanger[WHITE]; - tensor[1] = pinnedShelter[WHITE]; - tensor += 2; - tensor[0] = popcount(attackedBy[WHITE] & kingFlank[BLACK][fileOf(blackKing)]); - tensor[1] = popcount(multiAttacks[WHITE] & kingFlank[BLACK][fileOf(blackKing)]); - tensor[2] = popcount(attackedBy[BLACK] & kingFlank[BLACK][fileOf(blackKing)]); - tensor[3] = popcount(multiAttacks[BLACK] & kingFlank[BLACK][fileOf(blackKing)]); - tensor += 4; - tensor[0] = popcount(safeChecks[WHITE][N-1]); - tensor[1] = popcount(safeChecks[WHITE][B-1]); - tensor[2] = popcount(safeChecks[WHITE][R-1]); - tensor[3] = popcount(safeChecks[WHITE][Q-1]); - tensor += 4; - tensor[0] = popcount(checks[WHITE][N-1]); - tensor[1] = popcount(checks[WHITE][B-1]); - tensor[2] = popcount(checks[WHITE][R-1]); - tensor[3] = popcount(checks[WHITE][Q-1]); - tensor += 4; - tensor[0] = popcount(innerShelters[BLACK]); - tensor[1] = popcount(outerShelters[BLACK]); - tensor += 2; - // Ring weakness attacks - tensor[0] += popcount(kingRing[BLACK] & weakSquares[BLACK]); - tensor[1] += popcount(outerRing[BLACK] & weakSquares[BLACK]); - tensor += 2; - tensor[0] += us == WHITE ? 1 : -1; - tensor++; - - tensor[P] = innerAttacks[BLACK][P]; - tensor[N] = innerAttacks[BLACK][N]; - tensor[B] = innerAttacks[BLACK][B]; - tensor[R] = innerAttacks[BLACK][R]; - tensor[Q] = innerAttacks[BLACK][Q]; - tensor += 5; - tensor[P] = outerAttacks[BLACK][P]; - tensor[N] = outerAttacks[BLACK][N]; - tensor[B] = outerAttacks[BLACK][B]; - tensor[R] = outerAttacks[BLACK][R]; - tensor[Q] = outerAttacks[BLACK][Q]; - tensor += 5; - tensor[0] = noQueenDanger[BLACK]; - tensor[1] = pinnedShelter[BLACK]; - tensor += 2; - tensor[0] = popcount(attackedBy[BLACK] & kingFlank[WHITE][fileOf(whiteKing)]); - tensor[1] = popcount(multiAttacks[BLACK] & kingFlank[WHITE][fileOf(whiteKing)]); - tensor[2] = popcount(attackedBy[WHITE] & kingFlank[WHITE][fileOf(whiteKing)]); - tensor[3] = popcount(multiAttacks[WHITE] & kingFlank[WHITE][fileOf(whiteKing)]); - tensor += 4; - tensor[0] += popcount(safeChecks[BLACK][N-1]); - tensor[1] += popcount(safeChecks[BLACK][B-1]); - tensor[2] += popcount(safeChecks[BLACK][R-1]); - tensor[3] += popcount(safeChecks[BLACK][Q-1]); - tensor += 4; - tensor[0] = popcount(checks[BLACK][N-1]); - tensor[1] = popcount(checks[BLACK][B-1]); - tensor[2] = popcount(checks[BLACK][R-1]); - tensor[3] = popcount(checks[BLACK][Q-1]); - tensor += 4; - tensor[0] = popcount(innerShelters[WHITE]); - tensor[1] = popcount(outerShelters[WHITE]); - tensor += 2; - // Ring weakness attacks - tensor[0] += popcount(kingRing[WHITE] & weakSquares[WHITE]); - tensor[1] += popcount(outerRing[WHITE] & weakSquares[WHITE]); - tensor += 2; - tensor[0] += us == BLACK ? 1 : -1; - tensor++; - - // Also assert the last element we wrote is the penultimate element - // assert(tensorStart + tensorSize - 2 == tensor); -} - - -/** - * @brief The convertToFeatures function converts a set of positions to a set of features - * @param filename The filename of the epd file - * @param output The output file to write the features to - */ -void convertToFeatures(std::string filename, std::string output) { - std::ifstream file(filename); - // Check if the file is open - if (!file.is_open()){ - std::cout << "Error: Could not open file " << filename << std::endl; - return; - } - // Open output in binary mode - std::ofstream out(output, std::ios::binary); - // Get the count of weights by getting the current eval weights - auto weights = getCurrentEvalWeights(); - U32 weightCount = weights.size(); - U32 PSQTweights = 6 * 64; // PSQTS + 2 king buckets - U32 entrySize = 1 + PSQTweights + weightCount / 2 + 1; // The entry size is the 1 (gamephase) + number of weights divided by 2 + 1, since we add the result at the end, but we don't need to write the features twice for each side - entrySize += KINGSAFETYCOLOREDPARAMS; - entrySize += COMPLEXITYFEATURES; - std::cout << "Allocating for:\n"; - std::cout << "\t1\tGame result\n"; - std::cout << "\t1\tGame phase\n"; - std::cout << "\t" << PSQTweights << "\tPsqt entries\n"; - std::cout << "\t" << weightCount / 2 << "\tLinear evaluation terms\n"; - std::cout << "\t" << KINGSAFETYCOLOREDPARAMS / 2 << "x2=" << KINGSAFETYCOLOREDPARAMS << "\tAdditional color-dependant king safety formula features\n"; - std::cout << "\t" << COMPLEXITYFEATURES << "\tAdditional complexity features\n"; - std::cout << "For a total of " << entrySize << " bytes per entry" << std::endl; - // Create buffer to store the features - S8* features = new S8[entrySize]; - // For each line in the file - std::string line; - Position pos; - U64 counter = 0; - while (std::getline(file, line)){ - // Clear the features - memset(features, 0, entrySize); - // Parse the line. It contains the FEN string and the result. They are separated by a ";", and the result is either w,d,b (white, draw, black) - std::vector tokens; - - std::string token; - std::istringstream tokenStream(line); - while (std::getline(tokenStream, token, ';')){ - tokens.push_back(token); - } - // Parse the position - if (pos.parseFEN((char*)tokens[0].c_str())){ - // Get the features - getEvalFeaturesTensor(&pos, features); - - // Assert we filled the features correctly. This is checked by checking the penultimate element of the features and checking if it is 1 or -1 - assert(features[entrySize - 2] == 1 || features[entrySize - 2] == -1); - // Get the result - if (tokens[1] == "w") features[entrySize - 1] = 1; - else if (tokens[1] == "d") features[entrySize - 1] = 0; - else features[entrySize - 1] = -1; - // Write the features to the output file - out.write((char*)features, entrySize); - } - // Increment the counter and report progress each 16384 positions - if (++counter % 16384 == 0){ - std::cout << "Processed " << counter << " positions...\r"; - } - } - // Report the final progress - std::cout << "Processed " << counter << " positions." << std::endl; - // Close the file - out.close(); - // Delete the features - delete[] features; -} \ No newline at end of file diff --git a/src/evaluation.h b/src/evaluation.h deleted file mode 100644 index ee59129..0000000 --- a/src/evaluation.h +++ /dev/null @@ -1,191 +0,0 @@ -#pragma once - -#include "BBmacros.h" -#include "Position.h" - -const PScore pawnTable[2][64] = { - { - S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) , - S(233, 417) ,S(211, 426) ,S(160, 402) ,S(201, 287) ,S(228, 160) ,S(182, 88) ,S(-3, 159) ,S(-5, 200) , - S(99, 398) ,S(126, 389) ,S(118, 346) ,S(129, 252) ,S(177, 156) ,S(218, 142) ,S(163, 174) ,S(108, 214) , - S(118, 286) ,S(117, 265) ,S(115, 243) ,S(116, 214) ,S(141, 184) ,S(138, 185) ,S(83, 216) ,S(79, 215) , - S(121, 231) ,S(116, 228) ,S(117, 215) ,S(113, 207) ,S(114, 194) ,S(105, 203) ,S(74, 213) ,S(64, 216) , - S(133, 203) ,S(149, 199) ,S(124, 214) ,S(116, 215) ,S(104, 210) ,S(91, 215) ,S(63, 221) ,S(61, 219) , - S(133, 198) ,S(165, 191) ,S(145, 208) ,S(101, 223) ,S(87, 220) ,S(77, 221) ,S(59, 225) ,S(61, 223) , - S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) , - }, - { - S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) , - S(-35, 256) ,S(-53, 215) ,S(187, 131) ,S(232, 152) ,S(223, 207) ,S(198, 281) ,S(176, 339) ,S(224, 333) , - S(122, 234) ,S(159, 220) ,S(225, 186) ,S(150, 174) ,S(137, 191) ,S(130, 251) ,S(113, 296) ,S(99, 314) , - S(99, 224) ,S(102, 225) ,S(138, 198) ,S(133, 192) ,S(122, 176) ,S(110, 203) ,S(108, 222) ,S(104, 246) , - S(92, 208) ,S(99, 216) ,S(117, 210) ,S(116, 199) ,S(115, 187) ,S(109, 190) ,S(96, 207) ,S(96, 218) , - S(106, 195) ,S(120, 204) ,S(111, 226) ,S(123, 216) ,S(111, 196) ,S(107, 197) ,S(104, 197) ,S(99, 207) , - S(108, 173) ,S(139, 201) ,S(135, 230) ,S(100, 230) ,S(102, 205) ,S(95, 201) ,S(99, 199) ,S(96, 213) , - S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) ,S(108, 203) , - }, -}; -const PScore knightTable[2][64] = { - { - S(323, 590) ,S(356, 664) ,S(381, 701) ,S(508, 663) ,S(503, 660) ,S(397, 686) ,S(471, 646) ,S(344, 556) , - S(488, 638) ,S(511, 661) ,S(551, 657) ,S(589, 685) ,S(578, 675) ,S(574, 646) ,S(516, 654) ,S(532, 627) , - S(460, 669) ,S(527, 668) ,S(551, 706) ,S(558, 705) ,S(569, 693) ,S(552, 692) ,S(518, 666) ,S(529, 645) , - S(509, 683) ,S(540, 682) ,S(566, 708) ,S(575, 721) ,S(573, 723) ,S(560, 708) ,S(543, 697) ,S(550, 675) , - S(509, 688) ,S(534, 689) ,S(535, 712) ,S(543, 719) ,S(557, 718) ,S(549, 704) ,S(559, 689) ,S(536, 686) , - S(468, 653) ,S(484, 674) ,S(500, 689) ,S(502, 713) ,S(515, 712) ,S(496, 688) ,S(500, 664) ,S(479, 649) , - S(451, 667) ,S(449, 680) ,S(469, 663) ,S(479, 682) ,S(489, 683) ,S(482, 666) ,S(453, 683) ,S(455, 675) , - S(429, 618) ,S(436, 666) ,S(459, 662) ,S(466, 681) ,S(465, 672) ,S(460, 656) ,S(461, 653) ,S(427, 654) , - }, - { - S(351, 577) ,S(449, 702) ,S(390, 750) ,S(504, 717) ,S(462, 723) ,S(341, 751) ,S(348, 708) ,S(269, 635) , - S(526, 689) ,S(486, 704) ,S(579, 692) ,S(564, 735) ,S(548, 737) ,S(520, 699) ,S(475, 700) ,S(470, 676) , - S(497, 713) ,S(481, 743) ,S(555, 747) ,S(547, 744) ,S(532, 749) ,S(526, 743) ,S(494, 707) ,S(462, 687) , - S(519, 740) ,S(524, 761) ,S(547, 763) ,S(544, 784) ,S(540, 772) ,S(537, 741) ,S(522, 710) ,S(502, 702) , - S(508, 748) ,S(537, 745) ,S(528, 756) ,S(532, 772) ,S(520, 761) ,S(516, 744) ,S(508, 719) ,S(499, 706) , - S(473, 699) ,S(485, 719) ,S(487, 726) ,S(497, 750) ,S(499, 748) ,S(490, 722) ,S(487, 689) ,S(475, 658) , - S(460, 716) ,S(455, 717) ,S(464, 701) ,S(476, 720) ,S(478, 718) ,S(468, 693) ,S(463, 698) ,S(450, 691) , - S(423, 676) ,S(458, 681) ,S(459, 703) ,S(459, 709) ,S(466, 708) ,S(464, 676) ,S(468, 661) ,S(435, 650) , - }, -}; -const PScore bishopTable[2][64] = { - { - S(474, 759) ,S(427, 752) ,S(436, 741) ,S(396, 753) ,S(381, 739) ,S(384, 737) ,S(525, 727) ,S(471, 747) , - S(471, 753) ,S(485, 751) ,S(516, 735) ,S(471, 735) ,S(482, 724) ,S(537, 703) ,S(491, 727) ,S(459, 716) , - S(524, 749) ,S(542, 740) ,S(532, 739) ,S(527, 733) ,S(547, 712) ,S(548, 720) ,S(523, 716) ,S(531, 726) , - S(519, 748) ,S(538, 737) ,S(530, 741) ,S(537, 744) ,S(562, 727) ,S(536, 708) ,S(548, 723) ,S(524, 720) , - S(517, 729) ,S(529, 730) ,S(531, 735) ,S(551, 731) ,S(541, 726) ,S(535, 720) ,S(538, 704) ,S(524, 716) , - S(521, 718) ,S(549, 721) ,S(545, 729) ,S(532, 724) ,S(533, 726) ,S(519, 721) ,S(525, 716) ,S(511, 720) , - S(535, 707) ,S(562, 703) ,S(535, 713) ,S(520, 720) ,S(508, 723) ,S(515, 711) ,S(514, 701) ,S(520, 708) , - S(533, 709) ,S(495, 721) ,S(509, 729) ,S(501, 722) ,S(496, 724) ,S(496, 733) ,S(509, 730) ,S(526, 710) , - }, - { - S(452, 766) ,S(481, 754) ,S(366, 767) ,S(394, 774) ,S(376, 794) ,S(377, 786) ,S(437, 787) ,S(453, 798) , - S(471, 757) ,S(455, 762) ,S(495, 747) ,S(467, 761) ,S(459, 772) ,S(493, 768) ,S(477, 785) ,S(447, 785) , - S(495, 784) ,S(492, 775) ,S(505, 781) ,S(521, 755) ,S(502, 762) ,S(519, 768) ,S(502, 776) ,S(509, 773) , - S(489, 775) ,S(514, 776) ,S(514, 766) ,S(520, 779) ,S(523, 776) ,S(503, 759) ,S(517, 765) ,S(490, 777) , - S(502, 755) ,S(510, 760) ,S(506, 771) ,S(523, 771) ,S(513, 770) ,S(511, 768) ,S(511, 749) ,S(499, 754) , - S(506, 758) ,S(509, 755) ,S(506, 764) ,S(507, 768) ,S(509, 766) ,S(510, 760) ,S(527, 749) ,S(507, 746) , - S(506, 719) ,S(522, 736) ,S(505, 744) ,S(494, 760) ,S(495, 757) ,S(513, 742) ,S(519, 723) ,S(522, 739) , - S(509, 723) ,S(484, 743) ,S(489, 761) ,S(482, 757) ,S(489, 752) ,S(494, 760) ,S(513, 754) ,S(529, 733) , - }, -}; -const PScore rookTable[2][64] = { - { - S(729, 1256) ,S(701, 1276) ,S(681, 1282) ,S(652, 1286) ,S(662, 1280) ,S(719, 1254) ,S(706, 1257) ,S(682, 1272) , - S(692, 1253) ,S(692, 1258) ,S(700, 1256) ,S(689, 1263) ,S(686, 1256) ,S(695, 1242) ,S(661, 1248) ,S(665, 1242) , - S(678, 1246) ,S(737, 1221) ,S(708, 1242) ,S(720, 1220) ,S(731, 1211) ,S(704, 1225) ,S(748, 1200) ,S(678, 1229) , - S(665, 1243) ,S(682, 1237) ,S(702, 1233) ,S(705, 1230) ,S(704, 1219) ,S(690, 1221) ,S(703, 1213) ,S(682, 1218) , - S(629, 1229) ,S(660, 1236) ,S(635, 1249) ,S(637, 1244) ,S(640, 1230) ,S(645, 1229) ,S(652, 1228) ,S(632, 1219) , - S(612, 1194) ,S(654, 1203) ,S(632, 1211) ,S(637, 1209) ,S(641, 1201) ,S(641, 1202) ,S(658, 1200) ,S(635, 1187) , - S(573, 1202) ,S(628, 1192) ,S(641, 1198) ,S(636, 1200) ,S(643, 1194) ,S(651, 1187) ,S(661, 1176) ,S(612, 1188) , - S(610, 1199) ,S(628, 1208) ,S(656, 1207) ,S(654, 1196) ,S(654, 1188) ,S(664, 1192) ,S(669, 1187) ,S(646, 1187) , - }, - { - S(685, 1326) ,S(686, 1329) ,S(694, 1334) ,S(631, 1339) ,S(655, 1326) ,S(633, 1342) ,S(670, 1329) ,S(676, 1324) , - S(657, 1306) ,S(670, 1310) ,S(703, 1300) ,S(658, 1328) ,S(686, 1313) ,S(665, 1316) ,S(642, 1326) ,S(650, 1315) , - S(672, 1290) ,S(750, 1262) ,S(733, 1279) ,S(720, 1268) ,S(714, 1268) ,S(676, 1293) ,S(700, 1278) ,S(643, 1300) , - S(664, 1286) ,S(693, 1283) ,S(699, 1282) ,S(692, 1281) ,S(707, 1270) ,S(677, 1281) ,S(667, 1281) ,S(644, 1285) , - S(622, 1275) ,S(659, 1291) ,S(639, 1296) ,S(635, 1288) ,S(644, 1278) ,S(626, 1289) ,S(624, 1292) ,S(622, 1272) , - S(625, 1231) ,S(664, 1259) ,S(642, 1263) ,S(636, 1257) ,S(644, 1247) ,S(622, 1258) ,S(630, 1261) ,S(617, 1247) , - S(558, 1245) ,S(656, 1233) ,S(651, 1242) ,S(638, 1246) ,S(642, 1238) ,S(630, 1246) ,S(629, 1239) ,S(595, 1247) , - S(623, 1223) ,S(643, 1251) ,S(653, 1260) ,S(649, 1244) ,S(653, 1237) ,S(642, 1248) ,S(636, 1247) ,S(638, 1242) , - }, -}; -const PScore queenTable[2][64] = { - { - S(1363, 2174) ,S(1387, 2189) ,S(1369, 2213) ,S(1339, 2271) ,S(1354, 2259) ,S(1408, 2229) ,S(1376, 2212) ,S(1384, 2176) , - S(1365, 2194) ,S(1308, 2246) ,S(1350, 2229) ,S(1289, 2299) ,S(1286, 2332) ,S(1429, 2220) ,S(1342, 2220) ,S(1363, 2184) , - S(1360, 2211) ,S(1372, 2173) ,S(1358, 2203) ,S(1358, 2225) ,S(1378, 2242) ,S(1355, 2276) ,S(1399, 2186) ,S(1405, 2193) , - S(1373, 2185) ,S(1348, 2244) ,S(1347, 2226) ,S(1338, 2277) ,S(1352, 2264) ,S(1381, 2233) ,S(1408, 2224) ,S(1399, 2197) , - S(1363, 2181) ,S(1365, 2239) ,S(1347, 2259) ,S(1358, 2284) ,S(1356, 2257) ,S(1375, 2243) ,S(1394, 2201) ,S(1395, 2184) , - S(1353, 2178) ,S(1379, 2183) ,S(1375, 2212) ,S(1376, 2197) ,S(1376, 2191) ,S(1385, 2200) ,S(1402, 2167) ,S(1401, 2153) , - S(1334, 2143) ,S(1373, 2134) ,S(1411, 2081) ,S(1402, 2147) ,S(1390, 2145) ,S(1407, 2123) ,S(1413, 2117) ,S(1411, 2121) , - S(1356, 2109) ,S(1382, 2083) ,S(1384, 2088) ,S(1393, 2124) ,S(1399, 2126) ,S(1392, 2106) ,S(1384, 2147) ,S(1394, 2096) , - }, - { - S(1379, 2311) ,S(1403, 2334) ,S(1387, 2356) ,S(1334, 2352) ,S(1346, 2330) ,S(1336, 2323) ,S(1347, 2298) ,S(1310, 2307) , - S(1381, 2329) ,S(1315, 2394) ,S(1418, 2336) ,S(1268, 2408) ,S(1275, 2362) ,S(1331, 2297) ,S(1274, 2336) ,S(1336, 2278) , - S(1336, 2387) ,S(1331, 2391) ,S(1337, 2378) ,S(1345, 2338) ,S(1337, 2305) ,S(1327, 2288) ,S(1337, 2269) ,S(1334, 2277) , - S(1369, 2348) ,S(1364, 2381) ,S(1349, 2382) ,S(1315, 2384) ,S(1318, 2358) ,S(1337, 2280) ,S(1342, 2299) ,S(1347, 2261) , - S(1375, 2313) ,S(1367, 2325) ,S(1355, 2346) ,S(1335, 2359) ,S(1336, 2364) ,S(1349, 2300) ,S(1364, 2283) ,S(1359, 2240) , - S(1380, 2242) ,S(1381, 2264) ,S(1362, 2305) ,S(1360, 2273) ,S(1359, 2280) ,S(1364, 2285) ,S(1378, 2245) ,S(1366, 2219) , - S(1358, 2225) ,S(1389, 2173) ,S(1397, 2169) ,S(1379, 2226) ,S(1378, 2239) ,S(1384, 2197) ,S(1377, 2215) ,S(1372, 2207) , - S(1365, 2164) ,S(1362, 2170) ,S(1367, 2187) ,S(1389, 2191) ,S(1391, 2227) ,S(1384, 2201) ,S(1377, 2204) ,S(1372, 2206) , - }, -}; -const PScore kingTable[2][64] = { - { - S(-34, -189) ,S(74, -92) ,S(74, -70) ,S(99, -50) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-16, -34) ,S(92, 25) ,S(137, 16) ,S(145, -1) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(38, 5) ,S(118, 48) ,S(147, 51) ,S(127, 45) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-28, 16) ,S(73, 45) ,S(87, 62) ,S(67, 71) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-29, -21) ,S(32, 29) ,S(52, 53) ,S(9, 70) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-41, -24) ,S(-24, 10) ,S(-10, 32) ,S(-27, 52) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(23, -63) ,S(-26, -17) ,S(-55, 16) ,S(-96, 24) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(26, -153) ,S(2, -75) ,S(-48, -33) ,S(-68, -53) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - }, - { - S(10, -187) ,S(23, 1) ,S(65, -33) ,S(86, -40) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-43, -33) ,S(46, 68) ,S(138, 10) ,S(160, 2) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(20, 14) ,S(185, 52) ,S(250, 37) ,S(148, 38) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-57, 19) ,S(90, 45) ,S(116, 66) ,S(76, 75) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-62, -13) ,S(32, 27) ,S(42, 59) ,S(31, 77) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(-32, -15) ,S(-17, 14) ,S(-4, 43) ,S(-11, 61) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(31, -52) ,S(-15, -5) ,S(-54, 29) ,S(-81, 33) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - S(33, -138) ,S(-3, -52) ,S(-52, -17) ,S(-60, -48) ,S(0, 0) ,S(0, 0) ,S(0, 0) ,S(0, 0) , - }, -}; - -constexpr PScore materialValues[5] = {S(108, 203), S(465, 657), S(476, 697), S(637, 1215), S(1358, 2211), }; -constexpr PScore knightMob[9] = {S(-41, -159), S(-22, -84), S(-11, -35), S(-4, -8), S(2, 5), S(7, 20), S(14, 20), S(24, 15), S(35, -8), }; -constexpr PScore bishopMob[14] = {S(-61, -206), S(-33, -133), S(-17, -81), S(-9, -52), S(2, -30), S(6, -9), S(11, 5), S(11, 14), S(13, 24), S(21, 27), S(29, 20), S(55, 5), S(64, 12), S(86, -32), }; -constexpr PScore rookMob[15] = {S(-25, -144), S(-33, -101), S(-25, -65), S(-24, -45), S(-23, -26), S(-25, -9), S(-21, 2), S(-16, 3), S(-12, 9), S(-4, 15), S(-4, 22), S(1, 27), S(2, 30), S(19, 12), S(81, -23), }; -constexpr PScore queenMob[28] = {S(-147, -389), S(-108, -402), S(-70, -314), S(-51, -229), S(-48, -131), S(-45, -74), S(-41, -35), S(-37, -15), S(-34, 7), S(-29, 21), S(-25, 30), S(-20, 36), S(-16, 39), S(-12, 43), S(-10, 44), S(-7, 43), S(-8, 40), S(-11, 40), S(-7, 35), S(-4, 24), S(10, -2), S(18, -24), S(17, -41), S(30, -68), S(6, -73), S(11, -102), S(-20, -74), S(-33, -37), }; - -constexpr Score gamephaseInc[12] = { 0, 1, 1, 2, 4, 0, 0, 1, 1, 2, 4, 0 }; - -//constexpr Score KSAMG = -2; -constexpr double KSCALEMG = 830.4420166015625; -constexpr double KSBMG = 1; -constexpr double KSCMG = -2.9159793853759766; -// constexpr Score KSAEG = -71; -constexpr double KSCALEEG = 200.08270263671875; -constexpr double KSBEG = 1; -constexpr double KSCEG = -0.3122755289077759; - -#define PAWNHASHSIZE 262144ULL - -struct PawnEvalHashEntry { - U64 hash; - PScore score; - BitBoard passers; // This can be shrinked to add more stuff and keep the alignement -}; - -extern PawnEvalHashEntry pawnEvalHash[PAWNHASHSIZE]; - -extern PScore PSQTs[2][12][64]; -/** -* @brief The initTables function initializes the material - positional tables -* @note This function is called once at the beginning of the program -*/ -void initTables(); - -/** - * @brief The pestoEval function evaluates the material and positional scores - * @param pos The position to evaluate - * @return The material and positional scores - */ -Score pestoEval(Position* pos); - -/** - * @brief The initTropism function initializes the tropism tables - * @note This is called at the start of the program - */ -void initTropism(); - -/** - * @brief The convertToFeatures function converts a set of positions to a set of features - * @param filename The filename of the epd file - * @param output The output file to write the features to - */ -void convertToFeatures(std::string filename, std::string output); \ No newline at end of file diff --git a/src/history.cpp b/src/history.cpp deleted file mode 100644 index 1a12b8b..0000000 --- a/src/history.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "history.h" -#include "types.h" -#include "BBmacros.h" -#include "move.h" -#include "Game.h" -#include - -// history table -S16 historyTable[2][NUM_SQUARES * NUM_SQUARES][4]; - -// capture history table -S16 captureHistoryTable[NUM_PIECES * NUM_SQUARES][6][4]; - -// counter move table -Move counterMoveTable[NUM_SQUARES * NUM_SQUARES]; - -// Continuation History table -S16 continuationHistoryTable[NUM_PIECES * NUM_SQUARES][NUM_PIECES * NUM_SQUARES]; - -// Correction History -S32 pawnsCorrHist[2][CORRHISTSIZE]; // stm - hash -S32 nonPawnsCorrHist[2][2][CORRHISTSIZE]; // stm - side - hash -S32 tripletCorrHist[10][2][CORRHISTSIZE]; // stm - hash - -void updateHH(SStack* ss, bool side, BitBoard threats, Depth depth, Move bestMove, Move *quietMoves, U16 quietsCount, Move *noisyMoves, U16 noisyCount) { - const S32 bonus = statBonus(depth); - const S32 malus = statMalus(depth); - if (okToReduce(bestMove)) { - // If bestMove is not noisy, we reduce the bonus of all other moves and increase the bonus of the bestMove - updateHistoryMove(side, threats, bestMove, bonus); - updateContHist(ss, bestMove, bonus); - for (int i = 0; i < quietsCount; i++) { - if (quietMoves[i] == bestMove) continue; - updateHistoryMove(side, threats, quietMoves[i], -malus); - updateContHist(ss, quietMoves[i], -malus); - } - } - else { - // If bestMove is noisy, we only reduce the bonus of all other noisy moves - updateCaptureHistory(bestMove, threats, bonus); - } - for (int i = 0; i < noisyCount; i++) { - if (noisyMoves[i] == bestMove) continue; - updateCaptureHistory(noisyMoves[i], threats, -malus); - } -} - -static inline void updateSingleCorrHist(S32& entry, const S32 bonus, const S32 weight){ - const S32 MAXCORRHIST = CORRHISTSCALE * MAXCORRHISTUNSCALED(); - const S32 MAXCORRHISTUPDATE = MAXCORRHIST * MAXCORRHISTMILLIUPDATE() / CORRECTIONGRANULARITY; - - S32 newValue = (entry * (256 - weight) + bonus * weight) / 256; - newValue = std::clamp(newValue, entry - MAXCORRHISTUPDATE, entry + MAXCORRHISTUPDATE); - entry = std::clamp(newValue, -MAXCORRHIST, MAXCORRHIST); -} - -void updateCorrHist(Position& pos, const Score bonus, const Depth depth){ - const bool side = pos.side; - const S64 scaledBonus = bonus * CORRHISTSCALE; - const S32 weight = 2 * std::min(1 + depth, 16); - - auto const& k = pos.ptKeys; - - auto& pawnEntry = pawnsCorrHist[side][pos.pawnHashKey % CORRHISTSIZE]; - auto& wNonPawnEntry = nonPawnsCorrHist[side][WHITE][pos.nonPawnKeys[WHITE] % CORRHISTSIZE]; - auto& bNonPawnEntry = nonPawnsCorrHist[side][BLACK][pos.nonPawnKeys[BLACK] % CORRHISTSIZE]; - - updateSingleCorrHist(pawnEntry, scaledBonus * pawnCorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(wNonPawnEntry, scaledBonus * nonPawnCorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(bNonPawnEntry, scaledBonus * nonPawnCorrUpdate() / CORRECTIONGRANULARITY, weight); - - updateSingleCorrHist(tripletCorrHist[0][side][(k[K] ^ k[P] ^ k[N]) % CORRHISTSIZE], scaledBonus * T0CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[1][side][(k[K] ^ k[P] ^ k[B]) % CORRHISTSIZE], scaledBonus * T1CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[2][side][(k[K] ^ k[P] ^ k[R]) % CORRHISTSIZE], scaledBonus * T2CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[3][side][(k[K] ^ k[P] ^ k[Q]) % CORRHISTSIZE], scaledBonus * T3CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[4][side][(k[K] ^ k[N] ^ k[B]) % CORRHISTSIZE], scaledBonus * T4CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[5][side][(k[K] ^ k[N] ^ k[R]) % CORRHISTSIZE], scaledBonus * T5CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[6][side][(k[K] ^ k[N] ^ k[Q]) % CORRHISTSIZE], scaledBonus * T6CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[7][side][(k[K] ^ k[B] ^ k[R]) % CORRHISTSIZE], scaledBonus * T7CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[8][side][(k[K] ^ k[B] ^ k[Q]) % CORRHISTSIZE], scaledBonus * T8CorrUpdate() / CORRECTIONGRANULARITY, weight); - updateSingleCorrHist(tripletCorrHist[9][side][(k[K] ^ k[R] ^ k[Q]) % CORRHISTSIZE], scaledBonus * T9CorrUpdate() / CORRECTIONGRANULARITY, weight); -} diff --git a/src/history.h b/src/history.h deleted file mode 100644 index ae338e4..0000000 --- a/src/history.h +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once -#include "BBmacros.h" -#include "types.h" -#include "constants.h" -#include "Position.h" - -// history table -extern S16 historyTable[2][NUM_SQUARES * NUM_SQUARES][4]; - -// capture history table -extern S16 captureHistoryTable[NUM_PIECES * NUM_SQUARES][NUM_PIECES / 2][4]; // The color of the captured piece is always the opposite of the color of the moving piece - -// counter move table -extern Move counterMoveTable[NUM_SQUARES * NUM_SQUARES]; - -// Continuation History table -extern S16 continuationHistoryTable[NUM_PIECES * NUM_SQUARES][NUM_PIECES * NUM_SQUARES]; - -constexpr S32 CORRHISTSIZE = 16384; -constexpr S32 CORRHISTSCALE = 256; -constexpr S32 CORRECTIONGRANULARITY = 1024; - -// Correction History -extern S32 pawnsCorrHist[2][CORRHISTSIZE]; -extern S32 nonPawnsCorrHist[2][2][CORRHISTSIZE]; - -extern S32 tripletCorrHist[10][2][CORRHISTSIZE]; // 10 is the number of triplet indexing of type KXY, with X and Y satisfying X != K, Y != K, X != Y - -struct SStack { - Move excludedMove = 0; - Score staticEval = 0; - Move move = 0; - Move killers[2] = {0, 0}; - S16* contHistEntry = continuationHistoryTable[0]; - - SStack() { - excludedMove = noMove; - staticEval = 0; - move = noMove; - killers[0] = killers[1] = noMove; - contHistEntry = continuationHistoryTable[0]; - } - - void wipe() { - excludedMove = noMove; - staticEval = 0; - move = noMove; - killers[0] = killers[1] = noMove; - contHistEntry = continuationHistoryTable[0]; - } -}; - -inline S32 indexFromTo(Square from, Square to) { - return from * 64 + to; -} - -inline S32 indexPieceTo(Piece piece, Square to) { - return piece * 64 + (to^56); // So that P to a8 (0 if we don't ^56) is not the same as indexPieceTo(nullMove), which is instead the same as p to a8, which is impossible. -} - -static inline S32 getThreatsIndexing(const BitBoard threats, const Move move){ - const BitBoard source = squareBB(moveSource(move)); - const BitBoard target = squareBB(moveTarget(move)); - return ((source & threats)>0) + 2*((target & threats)>0); -} - -static inline S32 statBonus(S32 depth){ - return std::min(maxHistoryBonus(), depth * depth * historyBonusQuadDepth() + depth * historyBonusLinDepth() + historyBonusOffset()); -} - -static inline S32 statMalus(S32 depth){ - return std::min(maxHistoryMalus(), depth * depth * historyMalusQuadDepth() + depth * historyMalusLinDepth() + historyMalusOffset()); -} - -#define MAXHISTORYABS 16384LL -void updateHH(SStack* ss, bool side, BitBoard threats, Depth depth, Move bestMove, Move *quietMoves, U16 quietsCount, Move *noisyMoves, U16 noisyCount); - -template -Score correctStaticEval(Position& pos, Score eval) { - - S32 corrected; - - eval = static_cast(std::clamp( - (eval * (220 - pos.fiftyMove) / 220) - , -mateValue, +mateValue)); - - if constexpr (doCorrHist){ - - const bool side = pos.side; - auto const& k = pos.ptKeys; - - const S32 bonus = - + pawnsCorrHist[side][pos.pawnHashKey % CORRHISTSIZE] * pawnCorrWeight() - + ( - + nonPawnsCorrHist[side][WHITE][pos.nonPawnKeys[WHITE] % CORRHISTSIZE] - + nonPawnsCorrHist[side][BLACK][pos.nonPawnKeys[BLACK] % CORRHISTSIZE] - ) * nonPawnCorrWeight() - + tripletCorrHist[0][side][(k[K] ^ k[P] ^ k[N]) % CORRHISTSIZE] * T0CorrWeight() - + tripletCorrHist[1][side][(k[K] ^ k[P] ^ k[B]) % CORRHISTSIZE] * T1CorrWeight() - + tripletCorrHist[2][side][(k[K] ^ k[P] ^ k[R]) % CORRHISTSIZE] * T2CorrWeight() - + tripletCorrHist[3][side][(k[K] ^ k[P] ^ k[Q]) % CORRHISTSIZE] * T3CorrWeight() - + tripletCorrHist[4][side][(k[K] ^ k[N] ^ k[B]) % CORRHISTSIZE] * T4CorrWeight() - + tripletCorrHist[5][side][(k[K] ^ k[N] ^ k[R]) % CORRHISTSIZE] * T5CorrWeight() - + tripletCorrHist[6][side][(k[K] ^ k[N] ^ k[Q]) % CORRHISTSIZE] * T6CorrWeight() - + tripletCorrHist[7][side][(k[K] ^ k[B] ^ k[R]) % CORRHISTSIZE] * T7CorrWeight() - + tripletCorrHist[8][side][(k[K] ^ k[B] ^ k[Q]) % CORRHISTSIZE] * T8CorrWeight() - + tripletCorrHist[9][side][(k[K] ^ k[R] ^ k[Q]) % CORRHISTSIZE] * T9CorrWeight() - ; - - corrected = eval + bonus / (CORRHISTSCALE * CORRECTIONGRANULARITY); - } - else corrected = eval; - - // Integral's fifty move scaling. I had previously tried sp's (200) but didn't get a passer - return corrected; -} - -void updateCorrHist(Position& pos, const Score bonus, const Depth depth); - -static inline void updateHistoryMove(const bool side, const BitBoard threats, const Move move, const S32 delta) { - S16 *current = &historyTable[side][indexFromTo(moveSource(move), moveTarget(move))][getThreatsIndexing(threats, move)]; - *current += delta - *current * abs(delta) / MAXHISTORYABS; -} - -static inline void updateCaptureHistory(Move move, const BitBoard threats, S32 delta) { - Piece captured = moveCapture(move); - S16 *current = &captureHistoryTable[indexPieceTo(movePiece(move), moveTarget(move))][captured == NOPIECE ? P : captured % 6][getThreatsIndexing(threats, move)]; // account for promotion - *current += delta - *current * abs(delta) / MAXHISTORYABS; -} - -static inline void updateContHistOffset(SStack* ss, const Move move, const S32 delta, const S32 offset){ - S16 *current = &(ss - offset)->contHistEntry[indexPieceTo(movePiece(move), moveTarget(move))]; - *current += delta - *current * abs(delta) / MAXHISTORYABS; -} - -static inline void updateContHist(SStack* ss, const Move move, const S32 delta){ - updateContHistOffset(ss, move, delta, 1); - updateContHistOffset(ss, move, delta, 2); - updateContHistOffset(ss, move, delta, 4); -} \ No newline at end of file diff --git a/src/magic.cpp b/src/magic.cpp deleted file mode 100644 index 1a2226b..0000000 --- a/src/magic.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "magic.h" -#include "BBmacros.h" -#include "movegen.h" -#include -#include -#include - -/** - * @brief The getMagicNumber function returns a 64 bit candidate for the magic number. It means that the number has a low hamming weight. - * @return A 64 bit candidate for the magic number. - */ -U64 getMagicNumber(){ - return getRandom64() & getRandom64() & getRandom64(); -} - -/** - * @brief The findMagicNumber function finds the magic number for a square, bitcount and slider type - * @param square The square. - * @param relevantBits The relevant bits count. - * @param sliderType The slider type. - * @return The magic number. - */ -U64 findMagicNumber(int square, int relevantBits, bool sliderType) { - // init occupancies - U64* occupancies = new U64[4096]; - - // init attack tables - U64* attacks = new U64[4096]; - - // init used attacks - U64* usedAttacks = new U64[4096]; - - // init attack mask for a current piece - U64 attackMask = sliderType ? maskBishopAttacks(square) : maskRookAttacks(square); - - // init occupancy indicies - int occupancy_indicies = 1 << relevantBits; - - // loop over occupancy indicies - for (int index = 0; index < occupancy_indicies; index++) - { - // init occupancies - occupancies[index] = setOccupancy(index, relevantBits, attackMask); - - // init attacks - attacks[index] = sliderType ? getBishopAttacksOnTheFly(square, occupancies[index]) : getRookAttacksOnTheFly(square, occupancies[index]); - } - - // test magic numbers loop - for (int random_count = 0; random_count < 100000000; random_count++) { - // generate magic number candidate - U64 magic_number = getMagicNumber(); - - // skip inappropriate magic numbers - if (popcount((attackMask * magic_number) & 0xFF00000000000000) < 6) - continue; - - // init used attacks - memset(usedAttacks, 0ULL, 4096 * sizeof(U64)); - - // init index & fail flag - int index, fail; - - // test magic index loop - for (index = 0, fail = 0; !fail && index < occupancy_indicies; index++) { - // init magic index - int magic_index = (int)((occupancies[index] * magic_number) >> (64 - relevantBits)); - - // if magic index works - if (usedAttacks[magic_index] == 0ULL) - // init used attacks - usedAttacks[magic_index] = attacks[index]; - - // otherwise - else if (usedAttacks[magic_index] != attacks[index]) - // magic index doesn't work - fail = 1; - } - - // if magic number works - if (!fail) { - // return it - delete[] occupancies; - delete[] attacks; - delete[] usedAttacks; - return magic_number; - } - } - - // if magic number doesn't work - std::cerr << "Magic number not found!" << std::endl; - delete[] occupancies; - delete[] attacks; - delete[] usedAttacks; - return 0ULL; -} - -/** - * @brief The initMagic function initializes the magic numbers for every square and slider type. - */ -void initMagic() { - // init magic numbers - for (int square = 0; square < 64; square++) { - // init magic numbers - // bishopMagicNumbers[square] = findMagicNumber(square, bishopRelevantBits[square], true); - // rookMagicNumbers[square] = findMagicNumber(square, rookRelevantBits[square], false); - } -} \ No newline at end of file diff --git a/src/magic.h b/src/magic.h deleted file mode 100644 index 7ca5323..0000000 --- a/src/magic.h +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once -#include "types.h" -#include "random.h" - -constexpr U64 rookMagicNumbers[] = { - 0x8a80104000800020ULL, - 0x140002000100040ULL, - 0x2801880a0017001ULL, - 0x100081001000420ULL, - 0x200020010080420ULL, - 0x3001c0002010008ULL, - 0x8480008002000100ULL, - 0x2080088004402900ULL, - 0x800098204000ULL, - 0x2024401000200040ULL, - 0x100802000801000ULL, - 0x120800800801000ULL, - 0x208808088000400ULL, - 0x2802200800400ULL, - 0x2200800100020080ULL, - 0x801000060821100ULL, - 0x80044006422000ULL, - 0x100808020004000ULL, - 0x12108a0010204200ULL, - 0x140848010000802ULL, - 0x481828014002800ULL, - 0x8094004002004100ULL, - 0x4010040010010802ULL, - 0x20008806104ULL, - 0x100400080208000ULL, - 0x2040002120081000ULL, - 0x21200680100081ULL, - 0x20100080080080ULL, - 0x2000a00200410ULL, - 0x20080800400ULL, - 0x80088400100102ULL, - 0x80004600042881ULL, - 0x4040008040800020ULL, - 0x440003000200801ULL, - 0x4200011004500ULL, - 0x188020010100100ULL, - 0x14800401802800ULL, - 0x2080040080800200ULL, - 0x124080204001001ULL, - 0x200046502000484ULL, - 0x480400080088020ULL, - 0x1000422010034000ULL, - 0x30200100110040ULL, - 0x100021010009ULL, - 0x2002080100110004ULL, - 0x202008004008002ULL, - 0x20020004010100ULL, - 0x2048440040820001ULL, - 0x101002200408200ULL, - 0x40802000401080ULL, - 0x4008142004410100ULL, - 0x2060820c0120200ULL, - 0x1001004080100ULL, - 0x20c020080040080ULL, - 0x2935610830022400ULL, - 0x44440041009200ULL, - 0x280001040802101ULL, - 0x2100190040002085ULL, - 0x80c0084100102001ULL, - 0x4024081001000421ULL, - 0x20030a0244872ULL, - 0x12001008414402ULL, - 0x2006104900a0804ULL, - 0x1004081002402ULL -}; - -constexpr U64 bishopMagicNumbers[] = { - 0x40040844404084ULL, - 0x2004208a004208ULL, - 0x10190041080202ULL, - 0x108060845042010ULL, - 0x581104180800210ULL, - 0x2112080446200010ULL, - 0x1080820820060210ULL, - 0x3c0808410220200ULL, - 0x4050404440404ULL, - 0x21001420088ULL, - 0x24d0080801082102ULL, - 0x1020a0a020400ULL, - 0x40308200402ULL, - 0x4011002100800ULL, - 0x401484104104005ULL, - 0x801010402020200ULL, - 0x400210c3880100ULL, - 0x404022024108200ULL, - 0x810018200204102ULL, - 0x4002801a02003ULL, - 0x85040820080400ULL, - 0x810102c808880400ULL, - 0xe900410884800ULL, - 0x8002020480840102ULL, - 0x220200865090201ULL, - 0x2010100a02021202ULL, - 0x152048408022401ULL, - 0x20080002081110ULL, - 0x4001001021004000ULL, - 0x800040400a011002ULL, - 0xe4004081011002ULL, - 0x1c004001012080ULL, - 0x8004200962a00220ULL, - 0x8422100208500202ULL, - 0x2000402200300c08ULL, - 0x8646020080080080ULL, - 0x80020a0200100808ULL, - 0x2010004880111000ULL, - 0x623000a080011400ULL, - 0x42008c0340209202ULL, - 0x209188240001000ULL, - 0x400408a884001800ULL, - 0x110400a6080400ULL, - 0x1840060a44020800ULL, - 0x90080104000041ULL, - 0x201011000808101ULL, - 0x1a2208080504f080ULL, - 0x8012020600211212ULL, - 0x500861011240000ULL, - 0x180806108200800ULL, - 0x4000020e01040044ULL, - 0x300000261044000aULL, - 0x802241102020002ULL, - 0x20906061210001ULL, - 0x5a84841004010310ULL, - 0x4010801011c04ULL, - 0xa010109502200ULL, - 0x4a02012000ULL, - 0x500201010098b028ULL, - 0x8040002811040900ULL, - 0x28000010020204ULL, - 0x6000020202d0240ULL, - 0x8918844842082200ULL, - 0x4010011029020020ULL -}; - -constexpr U32 bishopRelevantBits[64] = { - 6, 5, 5, 5, 5, 5, 5, 6, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 7, 7, 7, 7, 5, 5, - 5, 5, 7, 9, 9, 7, 5, 5, - 5, 5, 7, 9, 9, 7, 5, 5, - 5, 5, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 5, 5, 5, 5, 5, 5, 6 -}; - -constexpr U32 rookRelevantBits[64] = { - 12, 11, 11, 11, 11, 11, 11, 12, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 12, 11, 11, 11, 11, 11, 11, 12 -}; - -/** - * @brief The getMagicNumber function returns a 64 bit candidate for the magic number. It means that the number has a low hamming weight. - * @return A 64 bit candidate for the magic number. - */ -U64 getMagicNumber(); - -/** - * @brief The findMagicNumber function finds the magic number for a square, bitcount and slider type - * @param square The square. - * @param relevantBits The relevant bits count. - * @param sliderType The slider type. - * @return The magic number. - */ -U64 findMagicNumber(int square, int relevantBits, bool sliderType); - -/** - * @brief The initMagic function initializes the magic numbers for every square and slider type. - */ -void initMagic(); \ No newline at end of file diff --git a/src/makefile b/src/makefile deleted file mode 100644 index 0d4f358..0000000 --- a/src/makefile +++ /dev/null @@ -1,13 +0,0 @@ -.PHONY: all debug release - -all: release - -release: - @$(MAKE) -sf build.mk TARGET=Release - -debug: - @$(MAKE) -sf build.mk TARGET=Debug - -clean: - @$(MAKE) -sf build.mk TARGET=Release clean - @$(MAKE) -sf build.mk TARGET=Debug clean diff --git a/src/move.cpp b/src/move.cpp deleted file mode 100644 index 337adbe..0000000 --- a/src/move.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "move.h" - -char getPieceChar(int piece) { - switch (piece) { - case P: return 'P'; - case N: return 'N'; - case B: return 'B'; - case R: return 'R'; - case Q: return 'Q'; - case K: return 'K'; - case p: return 'p'; - case n: return 'n'; - case b: return 'b'; - case r: return 'r'; - case q: return 'q'; - case k: return 'k'; - default: return '.'; - } -} - -char getPromotionPieceChar(int piece) { - switch (piece) { - case P: case p: return 'p'; - case N: case n: return 'n'; - case B: case b: return 'b'; - case R: case r: return 'r'; - case Q: case q: return 'q'; - case K: case k: return 'k'; - default: return ' '; - } -} - -int charToPiece(char piece) { - switch (piece) { - case 'P': return P; - case 'N': return N; - case 'B': return B; - case 'R': return R; - case 'Q': return Q; - case 'K': return K; - case 'p': return p; - case 'n': return n; - case 'b': return b; - case 'r': return r; - case 'q': return q; - case 'k': return k; - default: return NOPIECE; - } -} - -Square squareFromName(const char* squareName) { - // We expect square names to be in the form of "a1" - // so we can just use the ASCII values to get the file and rank - // and then multiply by 8 to get the square number - U8 rank = 7 - (squareName[1] - '1'); - U8 file = squareName[0] - 'a'; - if (rank > 7 || file > 7) { - return noSquare; - } - return rank * 8 + file; -} \ No newline at end of file diff --git a/src/move.h b/src/move.h deleted file mode 100644 index 2ca5f0e..0000000 --- a/src/move.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once -#include -#include "BBmacros.h" -#include -#include -/* -0000 0000 0000 0000 0000 00xx xxxx source square 0x3f -0000 0000 0000 0000 xxxx xx00 0000 target square 0xfc0 -0000 0000 0000 xxxx 0000 0000 0000 piece 0xf000 -0000 0000 xxxx 0000 0000 0000 0000 captured piece 0xf0000 -0000 xxxx 0000 0000 0000 0000 0000 promoted piece 0xf00000 - -0001 0000 0000 0000 0000 0000 0000 double push flag 0x200000 -0010 0000 0000 0000 0000 0000 0000 enpassant flag 0x400000 -0100 0000 0000 0000 0000 0000 0000 castling flag 0x800000 -1000 0000 0000 0000 0000 0000 0000 check flag 0x1000000 -*/ - - -#define encodeMove(source, target, piece, capture, promotion, doubleP, enpassant, castle, check) \ - ((source) | \ - ((target) << 6) | \ - ((piece) << 12) | \ - ((capture) << 16) | \ - ((promotion) << 20) | \ - ((doubleP) << 24) | \ - ((enpassant) << 25) | \ - ((castle) << 26) | \ - ((check) << 27)) - -#define moveSource(move) ((move) & 0x3f) -#define moveTarget(move) (((move) & 0xfc0) >> 6) -#define movePiece(move) (((move) & 0xf000) >> 12) -#define moveCapture(move) (((move) & 0xf0000) >> 16) -#define movePromotion(move) (((move) & 0xf00000) >> 20) -#define isDoublePush(move) (((move) >> 24) & 1) -#define isEnPassant(move) (((move) >> 25) & 1) -#define isCastling(move) (((move) >> 26) & 1) -#define isCheck(move) (((move) >> 27) & 1) -#define setCheck(move) ((move) |= (1 << 27)) - -#define isCapture(move) ((((move) & 0xf0000) >> 16) != NOPIECE) -#define isPromotion(move) ((((move) & 0xf00000) >> 20) != NOPIECE) -#define okToReduce(move) (! (isCapture(move) || isPromotion(move))) -#define onlyMove(move) ((move) & 0x2fffffff) -#define getScore(move) ((move) >> 32) - -#define NULLMOVE encodeMove(a8,a8,NOPIECE,NOPIECE,NOPIECE,false,false,false,false) -#define isOk(move) ((move & 0xfff) != 0) - -#define sameMovePos(move1,move2) (((move1) & 0xffff) == ((move2) & 0xffff)) // To compare two pseudolegal moves in the same position, it is enough to compare the source, target and piece - -/** - * @brief The getPieceChar function returns the character of a piece. - * @param piece The piece to get the character of. - * @return The character of the piece. - */ -char getPieceChar(int piece); - -/** - * @brief The getPromotionPieceChar function returns the character of a promotion piece. - * @param piece The piece to get the character of. - * @return The character of the piece. - * @note This function is used for the promotion piece in the UCI protocol, since pieces are always in lowercase, despite the side to move. - */ -char getPromotionPieceChar(int piece); - -/** - * @brief The charToPiece function returns the piece of a character. - * @param piece The character to get the piece of. - * @return The piece of the character. - */ -int charToPiece(char piece); - -/** - * @brief The squareFromName function returns the square of a square name. - * @param squareName The pointer to a string containing the square name. - * @return The square of the square name. - */ -Square squareFromName(const char* squareName); - -struct MoveList { - //moves - ScoredMove moves[256] = { 0 }; - //move count - U8 count = 1; - // clear function - inline void clear() { - count = 1; - } - -}; - -inline void printMove(ScoredMove move){ - if (isPromotion(move)){ - std::cout << coords[moveSource(move)] << coords[moveTarget(move)] << getPromotionPieceChar(movePromotion(move)); - } - else { - std::cout << coords[moveSource(move)] << coords[moveTarget(move)]; - } -} - -inline std::string getMoveString(ScoredMove move){ - std::stringstream ss; - if (isPromotion(move)){ - ss << coords[moveSource(move)] << coords[moveTarget(move)] << getPromotionPieceChar(movePromotion(move)); - } - else { - ss << coords[moveSource(move)] << coords[moveTarget(move)]; - } - return ss.str(); -} - -inline PackedMove packMove(Move move) { - return (move & 0xfff) | (movePromotion(move) << 12); -} - -inline bool packedMoveCompare(PackedMove m1, Move m2) { - return packMove(m2) == m1; -} diff --git a/src/movegen.cpp b/src/movegen.cpp deleted file mode 100644 index 681277a..0000000 --- a/src/movegen.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#include "movegen.h" -#include "BBmacros.h" -#include "magic.h" -#include "tables.h" - -/** - * @brief The maskPawnAttacks function returns the pawn attacks mask for a given square. - * @param square The square. - * @param side The side. - * @return The pawn attacks mask for a given square. - */ -BitBoard maskPawnAttacks(int square, int side){ - BitBoard attacks = 0; - BitBoard bb = squareBB(square); - if(side == WHITE){ - if (bb & (notFile(7))) attacks |= (bb >> 7); - if (bb & (notFile(0))) attacks |= (bb >> 9); - } - else{ - if (bb & (notFile(0))) attacks |= (bb << 7); - if (bb & (notFile(7))) attacks |= (bb << 9); - } - return attacks; -} - -/** - * @brief The maskBishopAttacks function returns the bishop attacks mask for a given square. - * @param square The square. - */ -BitBoard maskBishopAttacks(int square){ - BitBoard attacks = 0ULL; - int r=0,f=0; - int tr = square/8, tf = square%8; - for (r = tr + 1, f = tf + 1; r <= 6 && f <= 6; r++, f++) attacks |= squareBB(r * 8 + f); - for (r = tr - 1, f = tf + 1; r >= 1 && f <= 6; r--, f++) attacks |= squareBB(r * 8 + f); - for (r = tr + 1, f = tf - 1; r <= 6 && f >= 1; r++, f--) attacks |= squareBB(r * 8 + f); - for (r = tr - 1, f = tf - 1; r >= 1 && f >= 1; r--, f--) attacks |= squareBB(r * 8 + f); - return attacks; -} - -/** - * @brief The maskRookAttacks function returns the rook attacks mask for a given square. - * @param square The square. - */ -BitBoard maskRookAttacks(int square){ - BitBoard attacks = 0; - int r=0,f=0; - int tr = square/8, tf = square%8; - for (r = tr + 1; r <= 6; r++) attacks |= squareBB(r * 8 + tf); - for (r = tr - 1; r >= 1; r--) attacks |= squareBB(r * 8 + tf); - for (f = tf + 1; f <= 6; f++) attacks |= squareBB(tr * 8 + f); - for (f = tf - 1; f >= 1; f--) attacks |= squareBB(tr * 8 + f); - return attacks; -} - -/** - * @brief The getBishopAttacksOnTheFly function returns the bishop attacks mask for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The bishop attacks mask for a given square and occupancy. - * @note This function is to be used for magic number search and not for move generation. - */ -BitBoard getBishopAttacksOnTheFly(int square, BitBoard occupancy){ - //results - BitBoard attacks = 0ULL; - - //init ranks & files - int r, f; - - //initialize target ranks & files - int tr = square / 8; - int tf = square & 0x7; - - //generate bishop attacks - - for (r = tr + 1, f = tf + 1; r <= 7 && f <= 7; r++, f++) { - BitBoard possB = squareBB(r * 8 + f); - attacks |= possB; - if (occupancy & possB) break; - } - for (r = tr - 1, f = tf + 1; r >= 0 && f <= 7; r--, f++) { - BitBoard possB = squareBB(r * 8 + f); - attacks |= possB; - if (occupancy & possB) break; - } - for (r = tr + 1, f = tf - 1; r <= 7 && f >= 0; r++, f--) { - BitBoard possB = squareBB(r * 8 + f); - attacks |= possB; - if (occupancy & possB) break; - } - for (r = tr - 1, f = tf - 1; r >= 0 && f >= 0; r--, f--) { - BitBoard possB = squareBB(r * 8 + f); - attacks |= possB; - if (occupancy & possB) break; - } - - //return attack map - return attacks; -} - -/** - * @brief The getRookAttacksOnTheFly function returns the rook attacks mask for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The rook attacks mask for a given square and occupancy. - * @note This function is to be used for magic number search and not for move generation. - */ -BitBoard getRookAttacksOnTheFly(int square, BitBoard occupancy){ - //results - BitBoard attacks = 0ULL; - - //init ranks & files - int r, f; - - //initialize target ranks & files - int tr = square / 8; - int tf = square & 0x7; - - //mask relevante bishop occupancy bits - - for (r = tr + 1; r <= 7; r++) { - BitBoard possB = squareBB(r * 8 + tf); - attacks |= possB; - if (occupancy & possB) break; - } - for (r = tr - 1; r >= 0; r--) { - BitBoard possB = squareBB(r * 8 + tf); - attacks |= possB; - if (occupancy & possB) break; - } - for (f = tf + 1; f <= 7; f++) { - BitBoard possB = squareBB(tr * 8 + f); - attacks |= possB; - if (occupancy & possB) break; - } - for (f = tf - 1; f >= 0; f--) { - BitBoard possB = squareBB(tr * 8 + f); - attacks |= possB; - if (occupancy & possB) break; - } - - //return attack map - return attacks; -} - -/** - * @brief The setOccupancy function sets the occupancy gor a given attack mask - * @param index The index. - * @param bitsInMask The relevant bits in the mask. - * @param attackMask The attack mask. - * @return The occupancy. - */ -BitBoard setOccupancy(int index, int bitsInMask, BitBoard attackMask){ - // occupancy map - BitBoard occupancy = 0ULL; - //loop over range of bits within attack mask - for (int i = 0; i < bitsInMask; i++) { - // get LS1b index of attack mask - Square square = popLsb(attackMask); - //check wheter occupancy is on board, if true populate occupancy - if (index & squareBB(i)) occupancy |= squareBB(square); - } - return occupancy; -} - - - -/** - * @brief The initSliderAttacks function initializes the slider attacks for every square and occupancy. - * @param sliderType The slider type. - */ -void initSliderAttacks(bool sliderType) { - //init bishop & rook masks - for (int square = 0; square < 64; square++) { //loop over squares - //init bishop & rook masks - bishopMasks[square] = maskBishopAttacks(square); - rookMasks[square] = maskRookAttacks(square); - - //init current mask - U64 attackMask = sliderType ? bishopMasks[square] : rookMasks[square]; - - //init relevant occupancy bit cnt - int relevantBitsCount = popcount(attackMask); - - //init occupancy indexs - int occupancyIndexs = squareBB(relevantBitsCount); - - //loop over occupancyIndexs - for (int index = 0; index < occupancyIndexs; index++) { - if (sliderType) { //first case - //init current occupancy variation - U64 occupancy = setOccupancy(index, relevantBitsCount, attackMask); - - //init magic index - int magicIndex = (occupancy * bishopMagicNumbers[square]) >> (64 - bishopRelevantBits[square]); - - //init bishopAttacks (finally) - bishopAttacks[square][magicIndex] = getBishopAttacksOnTheFly(square, occupancy); - } //second case - else { - //init current occupancy variation - U64 occupancy = setOccupancy(index, relevantBitsCount, attackMask); - - //init magic index - int magicIndex = (occupancy * rookMagicNumbers[square]) >> (64 - rookRelevantBits[square]); - - //init bishopAttacks (finally) - rookAttacks[square][magicIndex] = getRookAttacksOnTheFly(square, occupancy); - } - } - } -} \ No newline at end of file diff --git a/src/movegen.h b/src/movegen.h deleted file mode 100644 index 79f0c99..0000000 --- a/src/movegen.h +++ /dev/null @@ -1,219 +0,0 @@ -#pragma once -#include "types.h" -#include "move.h" -#include "tables.h" -#include "magic.h" -#include "BBmacros.h" - -constexpr BitBoard pawnAttacks[2][64] = { - { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0x5, 0xa, 0x14, 0x28, 0x50, 0xa0, 0x40, - 0x200, 0x500, 0xa00, 0x1400, 0x2800, 0x5000, 0xa000, 0x4000, - 0x20000, 0x50000, 0xa0000, 0x140000, 0x280000, 0x500000, 0xa00000, 0x400000, - 0x2000000, 0x5000000, 0xa000000, 0x14000000, 0x28000000, 0x50000000, 0xa0000000, 0x40000000, - 0x200000000, 0x500000000, 0xa00000000, 0x1400000000, 0x2800000000, 0x5000000000, 0xa000000000, 0x4000000000, - 0x20000000000, 0x50000000000, 0xa0000000000, 0x140000000000, 0x280000000000, 0x500000000000, 0xa00000000000, 0x400000000000, - 0x2000000000000, 0x5000000000000, 0xa000000000000, 0x14000000000000, 0x28000000000000, 0x50000000000000, 0xa0000000000000, 0x40000000000000 - }, - { - 0x200, 0x500, 0xa00, 0x1400, 0x2800, 0x5000, 0xa000, 0x4000, - 0x20000, 0x50000, 0xa0000, 0x140000, 0x280000, 0x500000, 0xa00000, 0x400000, - 0x2000000, 0x5000000, 0xa000000, 0x14000000, 0x28000000, 0x50000000, 0xa0000000, 0x40000000, - 0x200000000, 0x500000000, 0xa00000000, 0x1400000000, 0x2800000000, 0x5000000000, 0xa000000000, 0x4000000000, - 0x20000000000, 0x50000000000, 0xa0000000000, 0x140000000000, 0x280000000000, 0x500000000000, 0xa00000000000, 0x400000000000, - 0x2000000000000, 0x5000000000000, 0xa000000000000, 0x14000000000000, 0x28000000000000, 0x50000000000000, 0xa0000000000000, 0x40000000000000, - 0x200000000000000, 0x500000000000000, 0xa00000000000000, 0x1400000000000000, 0x2800000000000000, 0x5000000000000000, 0xa000000000000000, 0x4000000000000000, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 - } -}; -constexpr BitBoard knightAttacks[64] = {0x20400, 0x50800, 0xa1100, 0x142200, 0x284400, 0x508800, 0xa01000, 0x402000, - 0x2040004, 0x5080008, 0xa110011, 0x14220022, 0x28440044, 0x50880088, 0xa0100010, 0x40200020, - 0x204000402, 0x508000805, 0xa1100110a, 0x1422002214, 0x2844004428, 0x5088008850, 0xa0100010a0, 0x4020002040, - 0x20400040200, 0x50800080500, 0xa1100110a00, 0x142200221400, 0x284400442800, 0x508800885000, 0xa0100010a000, 0x402000204000, - 0x2040004020000, 0x5080008050000, 0xa1100110a0000, 0x14220022140000, 0x28440044280000, 0x50880088500000, 0xa0100010a00000, 0x40200020400000, - 0x204000402000000, 0x508000805000000, 0xa1100110a000000, 0x1422002214000000, 0x2844004428000000, 0x5088008850000000, 0xa0100010a0000000, 0x4020002040000000, - 0x400040200000000, 0x800080500000000, 0x1100110a00000000, 0x2200221400000000, 0x4400442800000000, 0x8800885000000000, 0x100010a000000000, 0x2000204000000000, - 0x4020000000000, 0x8050000000000, 0x110a0000000000, 0x22140000000000, 0x44280000000000, 0x88500000000000, 0x10a00000000000, 0x20400000000000}; - -constexpr BitBoard kingAttacks[64] = {0x302, 0x705, 0xe0a, 0x1c14, 0x3828, 0x7050, 0xe0a0, 0xc040, - 0x30203, 0x70507, 0xe0a0e, 0x1c141c, 0x382838, 0x705070, 0xe0a0e0, 0xc040c0, - 0x3020300, 0x7050700, 0xe0a0e00, 0x1c141c00, 0x38283800, 0x70507000, 0xe0a0e000, 0xc040c000, - 0x302030000, 0x705070000, 0xe0a0e0000, 0x1c141c0000, 0x3828380000, 0x7050700000, 0xe0a0e00000, 0xc040c00000, - 0x30203000000, 0x70507000000, 0xe0a0e000000, 0x1c141c000000, 0x382838000000, 0x705070000000, 0xe0a0e0000000, 0xc040c0000000, - 0x3020300000000, 0x7050700000000, 0xe0a0e00000000, 0x1c141c00000000, 0x38283800000000, 0x70507000000000, 0xe0a0e000000000, 0xc040c000000000, - 0x302030000000000, 0x705070000000000, 0xe0a0e0000000000, 0x1c141c0000000000, 0x3828380000000000, 0x7050700000000000, 0xe0a0e00000000000, 0xc040c00000000000, - 0x203000000000000, 0x507000000000000, 0xa0e000000000000, 0x141c000000000000, 0x2838000000000000, 0x5070000000000000, 0xa0e0000000000000, 0x40c0000000000000}; -// bishop attack masks -extern BitBoard bishopMasks[64]; -// rook attack masks -extern BitBoard rookMasks[64]; -// bishop attacks table -extern BitBoard bishopAttacks[64][512]; -// rook attacks table -extern BitBoard rookAttacks[64][4096]; - -constexpr BitBoard wKCastleMask = squareBB(f1) | squareBB(g1); -constexpr BitBoard wQCastleMask = squareBB(d1) | squareBB(c1) | squareBB(b1); -constexpr BitBoard bKCastleMask = squareBB(f8) | squareBB(g8); -constexpr BitBoard bQCastleMask = squareBB(d8) | squareBB(c8) | squareBB(b8); - -// castling rights update constants -constexpr S32 castlingRights[64] = { - 7, 15, 15, 15, 3, 15, 15, 11, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 13, 15, 15, 15, 12, 15, 15, 14 -}; - -/** - * @brief The setOccupancy function sets the occupancy gor a given attack mask - * @param index The index. - * @param bitsInMask The relevant bits in the mask. - * @param attackMask The attack mask. - * @return The occupancy. - */ -BitBoard setOccupancy(int index, int bitsInMask, BitBoard attackMask); - -/** - * @brief The maskPawnAttacks function returns the pawn attacks mask for a given square. - * @param square The square. - * @param side The side. - * @return The pawn attacks mask for a given square. - */ -BitBoard maskPawnAttacks(int square, int side); - -/** - * @brief The maskBishopAttacks function returns the bishop attacks mask for a given square. - * @param square The square. - */ -BitBoard maskBishopAttacks(int square); - -/** - * @brief The maskRookAttacks function returns the rook attacks mask for a given square. - * @param square The square. - */ -BitBoard maskRookAttacks(int square); - -/** - * @brief The getBishopAttacksOnTheFly function returns the bishop attacks mask for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The bishop attacks mask for a given square and occupancy. - * @note This function is to be used for magic number search and not for move generation. - */ -BitBoard getBishopAttacksOnTheFly(int square, BitBoard occupancy); - -/** - * @brief The getRookAttacksOnTheFly function returns the rook attacks mask for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The rook attacks mask for a given square and occupancy. - * @note This function is to be used for magic number search and not for move generation. - */ -BitBoard getRookAttacksOnTheFly(int square, BitBoard occupancy); - -/** - * @brief The initSliderAttacks function initializes the slider attacks for every square and occupancy. - * @param sliderType The slider type. - */ -void initSliderAttacks(bool sliderType); - - -/** - * @brief The getBishopAttack function returns the bishop attacks for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The bishop attack table. - */ -inline BitBoard getBishopAttack(int square, U64 occupancy) { - // get bishop attacks assuming current board occupancy - occupancy &= bishopMasks[square]; - occupancy *= bishopMagicNumbers[square]; - occupancy >>= 64ULL - (U64)bishopRelevantBits[square]; - - // return bishop attacks - return bishopAttacks[square][occupancy]; -} - -/** - * @brief The getRookAttack function returns the rook attacks for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The rook attack table. - */ -inline BitBoard getRookAttack(int square, U64 occupancy) { - // get rook attacks assuming current board occupancy - occupancy &= rookMasks[square]; - occupancy *= rookMagicNumbers[square]; - occupancy >>= 64ULL - (U64)rookRelevantBits[square]; - - // return rook attacks - return rookAttacks[square][occupancy]; -} - -/** - * @brief The getQueenAttack function returns the queen attacks for a given square and occupancy. - * @param square The square. - * @param occupancy The occupancy. - * @return The queen attack table. - */ -inline BitBoard getQueenAttack(int square, U64 occupancy) { - return getBishopAttack(square, occupancy) | getRookAttack(square, occupancy); -} - -template -static inline BitBoard makePawnAttacks(BitBoard pawns){ - if constexpr (side == WHITE) return ((pawns & notFile(0)) >> 9) | ((pawns & notFile(7)) >> 7); - else return ((pawns & notFile(0)) << 7) | ((pawns & notFile(7)) << 9); -} - -/** - * @brief The xrayRookAttacks function determines the xray rook attacks for a given square, blockers and occupancy - * @param occupancy The occupancy. - * @param blockers The blockers. - * @param square The square. - * @return The xray rook attacks. - */ -inline BitBoard xRayRookAttacks(BitBoard occupancy, BitBoard blockers, Square square){ - BitBoard attacks = getRookAttack(square, occupancy); // First, we generate normal rook attacks - blockers &= attacks; // Then, we remove the blockers (the candidate pinned pieces) from the attacks - return attacks ^ getRookAttack(square, occupancy ^ blockers); // Then we calculate attacks like if the blockers were not there. Finally we only take those attacks only in this new set of blockers. -} - -/** - * @brief The xrayBishopAttacks function determines the xray bishop attacks for a given square, blockers and occupancy - * @param occupancy The occupancy. - * @param blockers The blockers. - * @param square The square. - * @return The xray bishop attacks. - */ -inline BitBoard xRayBishopAttacks(BitBoard occupancy, BitBoard blockers, Square square){ - BitBoard attacks = getBishopAttack(square, occupancy); // First, we generate normal bishop attacks - blockers &= attacks; // Then, we remove the blockers (the candidate pinned pieces) from the attacks - return attacks ^ getBishopAttack(square, occupancy ^ blockers); // Then we calculate attacks like if the blockers were not there. Finally we only take those attacks only in this new set of blockers. -} - -/** - * @brief The getPinnedPieces function returns the squares of a certain bitboard that are pinned to a certain square. - * @param occupancy The general occupancy. - * @param ownPieces The own pieces. (the pieces that are candidates to be pinned) - * @param pinSquare The square that is pinned. - * @param opRQ The opponent's Rook and Queen bitboard. - * @param opBQ The opponent's Bishop and Queen bitboard. - * @return The pinned pieces, if any. - */ -inline BitBoard getPinnedPieces(BitBoard occupancy, BitBoard ownPieces, Square pinSquare, BitBoard opRQ, BitBoard opBQ){ - BitBoard pinned = 0; - BitBoard pinner = (xRayRookAttacks(occupancy, ownPieces, pinSquare) & opRQ) | (xRayBishopAttacks(occupancy, ownPieces, pinSquare) & opBQ); // We generate the pinners for the rooks - while (pinner){ - Square sq = popLsb(pinner); - pinned |= squaresBetween[sq][pinSquare]; // We add the squares between the pin square and the pinner to the pinned pieces - } - // Only return own pieces - return pinned & ownPieces; -} \ No newline at end of file diff --git a/src/random.cpp b/src/random.cpp deleted file mode 100644 index c9eb795..0000000 --- a/src/random.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "random.h" -U64 state = 123456789; - -/** - * @brief The getRandom32 function returns a random 32 bit integer. - * @return A random 32 bit integer. - * @note This function updates the internal state of the random number generator. - */ -U32 getRandom32() { - U32 number = state; - number ^= number << 13; - number ^= number >> 17; - number ^= number << 5; - state = number; - return number; -} - -/** - * @brief The getRandom64 function returns a random 64 bit integer. - * @return A random 64 bit integer. - * @note This function updates the internal state of the random number generator. - */ -U64 getRandom64(){ - U64 number = state; - number ^= number << 13; - number ^= number >> 7; - number ^= number << 17; - state = number; - return number; -} diff --git a/src/random.h b/src/random.h deleted file mode 100644 index 2215c02..0000000 --- a/src/random.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "types.h" - -extern U64 state; - -/** - * @brief The getRandom32 function returns a random 32 bit integer. - * @return A random 32 bit integer. - * @note This function updates the internal state of the random number generator. - */ -U32 getRandom32(); - -/** - * @brief The getRandom64 function returns a random 64 bit integer. - * @return A random 64 bit integer. - * @note This function updates the internal state of the random number generator. - */ -U64 getRandom64(); \ No newline at end of file diff --git a/src/search.cpp b/src/search.cpp deleted file mode 100644 index 4ecc930..0000000 --- a/src/search.cpp +++ /dev/null @@ -1,797 +0,0 @@ -#include "Game.h" -#include "tables.h" -#include "constants.h" -#include "history.h" -#include "zobrist.h" -#include "evaluation.h" -#include "uci.h" -#include "tt.h" -#include -#include -#include -// Global var to debug the SE implementation -S64 seCandidates = 0; -U64 seActivations = 0; -S64 avgDist = 0; - - -static inline Score mateIn(Ply ply) { return ((mateScore) - (ply)); } -static inline Score matedIn(Ply ply) { return ((-mateScore) + (ply)); } -static inline Score randomizedDrawScore(U64 nodes) { return 4 - (nodes & 7); } -static inline Score adjustMateScore(Score score, Ply ply) { return score + ply * (score < -mateValue) - ply * (score > mateValue); } - -inline bool okToReducePacked(Position &pos, PackedMove move) -{ - return !((movePiece(move) != NOPIECE) | (pos.pieceOn(moveTarget(move)) != NOPIECE)); -} - -static inline S32 reduction(Depth d, U16 m, bool isQuiet, bool isPv) -{ - return reductionTable[isQuiet][std::min((int)d,63)][std::min((int)m,63)] - lmrPV() * isPv; -} - -static inline Score futilityMargin(Depth depth, bool improving) -{ - return futilityMarginDelta() * (depth - improving); -} - -static inline int sortTTUp(MoveList &ml, PackedMove ttMove) -{ - for (int i = 0; i < ml.count; i++) - { - if (packedMoveCompare(ttMove, (Move)ml.moves[i])) - { - ml.moves[0] = ml.moves[i]; - ml.moves[i] = 0; - return 0; - } - } - return 1; -} - -static inline void updateKillers(SStack* ss, Move killerMove) -{ - if (ss->killers[0] != killerMove) - { - ss->killers[1] = ss->killers[0]; - ss->killers[0] = killerMove; - } -} - -static inline void updateCounters(Move counter, Move lastMove) -{ - if (lastMove) counterMoveTable[indexFromTo(moveSource(lastMove), moveTarget(lastMove))] = counter; -} - -static inline void clearKillers(SStack *ss) -{ - ss->killers[0] = noMove; - ss->killers[1] = noMove; -} - -Score Game::search(Score alpha, Score beta, Depth depth, bool cutNode, SStack *ss) -{ - // Comms - if (nodes >= hardNodesLimit) - stopped = true; - if ((nodes & comfrequency) == 0) - communicate(); - if (stopped) - return 0; - - assert(pos.hashKey == pos.generateHashKey()); - assert(pos.pawnHashKey == pos.generatePawnHashKey()); - assert(pos.nonPawnKeys[WHITE] == pos.generateNonPawnHashKey(WHITE)); - assert(pos.nonPawnKeys[BLACK] == pos.generateNonPawnHashKey(BLACK)); - assert(pos.ptKeys[P] == pos.generatePtHashKey

()); - assert(pos.ptKeys[N] == pos.generatePtHashKey()); - assert(pos.ptKeys[B] == pos.generatePtHashKey()); - assert(pos.ptKeys[R] == pos.generatePtHashKey()); - assert(pos.ptKeys[Q] == pos.generatePtHashKey()); - assert(pos.ptKeys[K] == pos.generatePtHashKey()); - - // Ply overflow - if (ply >= maxPly) - return evaluate(); - const bool RootNode = ply == 0; - const bool PVNode = (beta - alpha) > 1; - - Score eval; - Score rawEval; // for corrhist - Score improvement; - bool improving = true; - const Move excludedMove = ss->excludedMove; - // Guard from pvlen editing when in singular extension - if (!excludedMove) - pvLen[ply] = ply; - - // Update seldepth - seldepth = std::max(Ply(seldepth), Ply(ply + 1)); - - const bool inCheck = pos.checkers; - - // Draws - mate distance - if (!RootNode) - { - if (isRepetition() || pos.fiftyMove >= 100 || pos.insufficientMaterial()) - return randomizedDrawScore(nodes); // Randomize draw score so that we try to explore different lines - - // Mate distance pruning - alpha = std::max(alpha, matedIn(ply)); - beta = std::min(beta, mateIn(ply + 1)); - if (alpha >= beta) - return alpha; - } - - //// TT probe - ttEntry *tte = excludedMove ? nullptr : probeTT(pos.hashKey); - const bool ttHit = tte; - const Score ttScore = ttHit ? adjustMateScore(tte->score, ply) : noScore; - const PackedMove ttMove = ttHit ? tte->bestMove : 0; - const U8 ttFlags = ttHit ? tte->agePvFlag : 0; - const U8 ttBound = ttFlags & hashEXACT; - const Depth ttDepth = ttHit ? tte->depth : 0; - - if (ttScore != noScore) - { - if (!PVNode && ttDepth >= depth) - { - if (ttBound == hashEXACT) - return ttScore; - if ((ttBound == hashLOWER)) - alpha = std::max(alpha, ttScore); - else if ((ttBound == hashUPPER)) - beta = std::min(beta, ttScore); - if (alpha >= beta) { - // Update best move history - // Square from = moveSource(ttMove); - // Square to = moveTarget(ttMove); - // updateHistoryBonus(&historyTable[pos.side][indexFromTo(from, to)], depth, true); - return ttScore; - } - } - } - - const bool ttPv = PVNode || (ttFlags & hashPVMove); - - // Clear killers - clearKillers(ss+1); - // Clear excluded move - (ss+1)->excludedMove = noMove; - - // Quiescence drop - if (depth <= 0) return quiescence(alpha, beta, ss); - - UndoInfo undoer = UndoInfo(pos); - - if (!excludedMove){ - if ((PVNode || cutNode) && depth >= IIRDepth() - 2*PVNode && (!ttMove || ttDepth + 3 < depth)) --depth; - } - - if (inCheck) - { - ss->staticEval = eval = rawEval = noScore; - improvement = 0; - improving = false; - goto skipPruning; - } - - // Get static eval of the position - if (ttHit) - { - // Check if the eval is stored in the TT - rawEval = tte->eval != noScore ? tte->eval : evaluate(); - eval = ss->staticEval = correctStaticEval(pos, rawEval); - // Also, we might be able to use the score as a better eval - if (ttScore != noScore && (ttBound == hashEXACT || (ttBound == hashUPPER && ttScore < eval) || (ttBound == hashLOWER && ttScore > eval))) - eval = ttScore; - } - else if (excludedMove){ - rawEval = eval = ss->staticEval; // We already have the eval from the main search in the current ss entry - improvement = 0; - improving = false; - goto skipPruning; - } - else { - rawEval = evaluate(); - eval = ss->staticEval = correctStaticEval(pos, rawEval); - // Store the eval in the TT if not in exclusion mode (in which we might already have the entry) - writeTT(pos.hashKey, noScore, rawEval, 0, hashNONE, 0, ply, PVNode, ttPv, age); - } - - improvement = [&](){ - if ((ss - 2)->staticEval != noScore) - return ss->staticEval - (ss - 2)->staticEval; - else if ((ss - 4)->staticEval != noScore) - return ss->staticEval - (ss - 4)->staticEval; - return 1; // speculative improvement to cut less - }(); - - // Calculate the improving flag - improving = improvement > 0; - - // Pruning time - if (!PVNode && !excludedMove) - { - // RFP - if (depth <= RFPDepth() && abs(eval) < mateValue && eval - std::max((Score)15,futilityMargin(depth, improving)) >= beta) // && !excludedMove) - return eval; - - // Razoring - if (depth <= razorDepth() && abs(eval) < mateValue && eval + razorQ1() + depth * razorQ2() < alpha && alpha < KNOWNWIN) - { - const Score razorScore = quiescence(alpha, beta, ss); - if (razorScore <= alpha) return razorScore; - } - - // Null move pruning - if (ply >= nmpPlies && - depth >= 3 && - eval >= beta && - ss->staticEval >= beta + nmpMarginBias() - depth * nmpDepthMargin() && - pos.hasNonPawns()) - { - - // make null move - makeNullMove(); - prefetch(&tt[hashEntryFor(pos.hashKey)]); - ss->move = noMove; - ss->contHistEntry = continuationHistoryTable[0]; - - Depth R = nmpQ1() + (depth / nmpDepthDivisor()) + std::min((eval - beta) / nmpScoreDivisor(), nmpQ2()) + improving; - Score nullScore = -search(-beta, -beta + 1, depth - R, !cutNode, ss + 1); - - undoNullMove(undoer); - - if (stopped) - return 0; - - if (nullScore >= beta) - { - if (nullScore >= mateValue) - nullScore = beta; - if (nmpPlies || depth <= 14) - return nullScore; - - // If the null move failed high, we can try a reduced search when depth is high. This is to avoid zugzwang positions - nmpPlies = ply + (depth - R) * 2 / 3; - Score verification = search(beta - 1, beta, depth - R, false, ss); - nmpPlies = 0; - - if (verification >= beta) - return nullScore; - } - } - } - -skipPruning: - - // Search - const Score origAlpha = alpha; - Score bestScore = noScore; - Move bestMove = noMove; - U16 moveSearched = 0; - bool skipQuiets = false; - - Move quiets[256], noisy[256]; - U16 quietsCount = 0, noisyCount = 0; - - MoveList moveList; - generateMoves(moveList, ss); - // Iterate through moves - for (int i = (ttMove ? sortTTUp(moveList, ttMove) : 1); i < moveList.count; i++) // Slot 0 is reserved for the tt move, wheter it is present or not - { - S32 currMoveScore = getScore(moveList.moves[i]); // - BADNOISYMOVE; - Move currMove = onlyMove(moveList.moves[i]); - if (sameMovePos(currMove, excludedMove)) continue; - const bool isQuiet = okToReduce(currMove); - const bool quietOrLosing = currMoveScore < COUNTERSCORE; - if (moveSearched){ - if (!skipQuiets) { - if (!PVNode && moveSearched >= lmpMargin[depth][improving]) skipQuiets = true; - if (!PVNode - && depth <= 8 - && !inCheck - && bestScore > -KNOWNWIN - && std::abs(alpha) < KNOWNWIN - && isQuiet - && ss->staticEval + futPruningAdd() + futPruningMultiplier() * depth <= alpha) - { - skipQuiets = true; - continue; - } - if (!PVNode && depth <= 4 && (isQuiet ? (currMoveScore - QUIETSCORE) : (currMoveScore - BADNOISYMOVE)) < ( historyPruningMultiplier() * depth) + historyPruningBias()){ - skipQuiets = true; - continue; - } - } - else if (quietOrLosing) continue; - const auto seeThresh = isQuiet - ? pvsSeeThresholdNoisy() * depth - : pvsSeeThresholdQuiet() * depth * depth - ; - if (quietOrLosing && depth <= pvsSeeMaxDepth() && !pos.SEE(currMove, seeThresh)) continue; - } - // assert ( - // i != 0 || !excludedMove || - // (excludedMove == currMove) - // ); - if (!currMove) continue; // || currMove == excludedMove - - // const bool givesCheck = isCheck(currMove) || pos.inCheck(); - - if (makeMove(currMove)) - { - // Prefetch tt - prefetch(&tt[hashEntryFor(pos.hashKey)]); - U64 nodesBefore = nodes; - // // Singular extension - Depth extension = 0; - if (!excludedMove){ - - if (i == 0 // Can only happen on ttMove - && !RootNode - && depth >= singularSearchDepth() - && (ttBound & hashLOWER) - && abs(ttScore) < mateValue - && ttDepth >= depth - 3 - ){ - // Increase singular candidates - //++seCandidates; - const Score singularBeta = ttScore - singularDepthMultiplier() * depth / 10; - const Depth singularDepth = (depth - 1) / 2; - ss->excludedMove = currMove; - undo(undoer, currMove); - const Score singularScore = search(singularBeta - 1, singularBeta, singularDepth, cutNode, ss); - makeMove(currMove); - ss->excludedMove = noMove; - - if (singularScore < singularBeta) { - extension = 1; - if (!PVNode && singularScore + doubleExtensionMargin() < singularBeta) { - extension = 2; - } - // Increase singular activations - // ++seActivations; - } - else if (singularBeta >= beta){ // Multicut - undo(undoer, currMove); - return singularBeta; - } - else if (ttScore >= beta){ - extension -= 1 + !PVNode; - } - else if (cutNode){ - extension = -1; - } - - // else{ - // std::cout << "info string Singular failed with score: " << singularScore << " beta: " << singularBeta << std::endl; - // } - // Update avg dist - //avgDist += singularScore - singularBeta; - } - else if (inCheck) - extension = 1; - } - cutNode |= extension < 0; - - Depth newDepth = std::max(0,depth - 1 + extension); - - ss->move = currMove; - ss->contHistEntry = continuationHistoryTable[indexPieceTo(movePiece(currMove), moveTarget(currMove))]; - - Score score; - - ++nodes; - - if (isQuiet) quiets[quietsCount++] = currMove; - else noisy[noisyCount++] = currMove; - // if (RootNode && depth >= LOGROOTMOVEDEPTH) std::cout << "info depth " << std::dec << (int)currSearch << " currmove " << getMoveString(currMove) << " currmovenumber " << moveSearched + 1 << " currmovescore " << currMoveScore << " hashfull " << hashfull(age) << std::endl; // << " kCoffs: " << kCoffs << "/" << kEncounters << std::endl; - - if (moveSearched > PVNode * 3 && depth >= 3 && (isQuiet || !ttPv)) - { - S32 granularR = reduction(depth, moveSearched, isQuiet, ttPv); - if (currMoveScore >= COUNTERSCORE) granularR -= lmrExpectedDecent(); - if (isQuiet){ - // R -= givesCheck; - granularR -= std::clamp((currMoveScore - QUIETSCORE) * RESOLUTION, -16000000LL, 16000000LL) / lmrQuietHistoryDivisor(); - if (cutNode) granularR += lmrQuietCutNode(); - if (ttPv) granularR -= cutNode * lmrQuietTTPV(); - } - else { - if (currMoveScore < QUIETSCORE) { - if (cutNode) granularR += lmrBadNoisyCutNode(); - granularR -= std::clamp((currMoveScore - BADNOISYMOVE) * RESOLUTION, -6000000LL, 12000000LL) / lmrNoisyHistoryDivisorA(); - } - else { - granularR -= std::clamp((currMoveScore - GOODNOISYMOVE - BADNOISYMOVE) * RESOLUTION, -6000000LL, 12000000LL) / lmrNoisyHistoryDivisorB(); - } - } - // The function looked cool on desmos - granularR -= lmrCieckA() * improvement / (std::abs(improvement * lmrCieckB() / 1000) + lmrCieckC()); - Depth R = granularR / RESOLUTION; - R = std::max(Depth(0), R); - R = std::min(Depth(newDepth - Depth(1)), R); - Depth reducedDepth = newDepth - R; - // Search at reduced depth - score = -search(-alpha - 1, -alpha, reducedDepth, true, ss + 1); - // If failed high on reduced search, research at full depth - if (score > alpha && R){ - bool deeper = score > bestScore + doDeeperMargin() + 2 * newDepth; - bool shallower = score < bestScore + 8; - newDepth += deeper - shallower; - score = -search(-alpha - 1, -alpha, newDepth, !cutNode, ss + 1); - if (isQuiet && (score <= alpha || score >= beta)){ - const auto bonus = score <= alpha ? -statMalus(newDepth) : statBonus(newDepth); - updateContHist(ss, currMove, bonus); - } - } - } - else - if (!PVNode || moveSearched) - score = -search(-alpha - 1, -alpha, newDepth, !cutNode, ss + 1); - - // Pvsearch - if (PVNode && (!moveSearched || score > alpha)) - score = -search(-beta, -alpha, newDepth, false, ss + 1); - - undo(undoer, currMove); - - - if (stopped) - return 0; - - if (RootNode) nodesPerMoveTable[indexFromTo(moveSource(currMove), moveTarget(currMove))] += nodes - nodesBefore; - - ++moveSearched; - - if (score > bestScore) { - bestScore = score; - if (score > alpha) { - bestMove = currMove; - - if (PVNode) { - pvTable[ply][ply] = currMove; - if (ply + 1 < maxPly) { - // Copy the pv from the next ply - for (int j = ply + 1; j < pvLen[ply + 1]; j++) - pvTable[ply][j] = pvTable[ply + 1][j]; - pvLen[ply] = pvLen[ply + 1]; - } - } - if (score >= beta) { - if (isQuiet) { - updateKillers(ss, currMove); - updateCounters(currMove, (ss - 1)->move); - } - updateHH(ss, pos.side, pos.threats, depth, currMove, quiets, quietsCount, noisy, noisyCount); - break; - } - alpha = score; - } - } - } - else - undo(undoer, currMove); - } - - //// Check for checkmate / - if (moveSearched == 0){ - return excludedMove ? alpha : (inCheck ? matedIn(ply) : randomizedDrawScore(nodes)); // Randomize draw score so that we try to explore different lines - // return inCheck ? matedIn(ply) : randomizedDrawScore(nodes); - } - // - // return inCheck ? matedIn(ply) : randomizedDrawScore(nodes); // Randomize draw score so that we try to explore different lines - - if (!stopped && !excludedMove){ - if (!inCheck - && (!bestMove || okToReduce(bestMove)) - && !(ttBound == hashLOWER && bestScore <= ss->staticEval) - && !(ttBound == hashUPPER && bestScore >= ss->staticEval)){ - updateCorrHist(pos, bestScore - ss->staticEval, depth); - } - U8 ttStoreFlag = bestScore >= beta ? hashLOWER : alpha != origAlpha ? hashEXACT : hashUPPER; - writeTT(pos.hashKey, bestScore, rawEval, depth, ttStoreFlag, bestMove, ply, PVNode, ttPv, age); - // writeTT(pos.hashKey, bestScore, ss->staticEval, depth, ttStoreFlag, bestMove, ply, false, PVNode); - } - - return bestScore; -} - -Score Game::quiescence(Score alpha, Score beta, SStack *ss) -{ - const bool inCheck = pos.checkers; - if (inCheck) - if (isRepetition()) - return randomizedDrawScore(nodes); // Randomize draw score so that we try to explore different lines - - Score bestScore; - Score rawEval; - - if (ply >= maxPly - 1) - return inCheck ? 0 : evaluate(); - - const bool PVNode = (beta - alpha) > 1; - - //// TT probe - ttEntry *tte = probeTT(pos.hashKey); //excludedMove ? nullptr : probeTT(pos.hashKey); - const bool ttHit = tte; - const Score ttScore = ttHit ? adjustMateScore(tte->score, ply) : noScore; - const PackedMove ttMove = ttHit ? tte->bestMove : 0; - const U8 ttFlags = ttHit ? tte->agePvFlag : 0; - const U8 ttBound = ttFlags & hashEXACT; - - if (ttScore != noScore) - { - if (!PVNode) - { - if (ttBound == hashEXACT) - return ttScore; - if ((ttBound == hashLOWER)) - alpha = std::max(alpha, ttScore); - else if ((ttBound == hashUPPER)) - beta = std::min(beta, ttScore); - if (alpha >= beta) { - // Update best move history - // Square from = moveSource(ttMove); - // Square to = moveTarget(ttMove); - // updateHistoryBonus(&historyTable[pos.side][indexFromTo(from, to)], depth, true); - return ttScore; - } - } - } - - const bool ttPv = PVNode || (ttFlags & hashPVMove); - - if (inCheck){ - ss->staticEval = bestScore = rawEval = noScore; - } - else if (ttHit){ - rawEval = tte->eval != noScore ? tte->eval : evaluate(); - ss->staticEval = bestScore = correctStaticEval(pos, rawEval); - if (ttScore != noScore && (ttBound == hashEXACT || (ttBound == hashUPPER && ttScore < bestScore) || (ttBound == hashLOWER && ttScore > bestScore))) - bestScore = ttScore; - } - else { - rawEval = evaluate(); - ss->staticEval = bestScore = correctStaticEval(pos, rawEval); - writeTT(pos.hashKey, noScore, rawEval, 0, hashNONE, 0, ply, PVNode, ttPv, age); - } - - if (bestScore >= beta) - return bestScore; - alpha = std::max(alpha, bestScore); - - // Generate moves - MoveList moveList; - - inCheck ? generateMoves(moveList, ss) : generateCaptures(moveList); - Score futility = inCheck ? -infinity : ss->staticEval + qsFutilityMargin(); - - UndoInfo undoer = UndoInfo(pos); - U16 moveCount = 0; - Move bestMove = noMove; - for (int i = sortTTUp(moveList, ttMove); i < moveList.count; i++) - { - Move move = onlyMove(moveList.moves[i]); - - // Move count pruning - if (!inCheck && moveCount >= 2) break; - - // SEE pruning : skip all moves that have see < of the adaptive capthist based threshold - if (!inCheck && moveCount && getScore(moveList.moves[i]) < GOODNOISYMOVE) - break; - - // Futility pruning - if (!inCheck && futility <= alpha && !pos.SEE(move, 1)){ - bestScore = std::max(bestScore, futility); - continue; - } - if (makeMove(move)) - { - // Prefetch tt - prefetch(&tt[hashEntryFor(pos.hashKey)]); - ss->move = move; - ss->contHistEntry = continuationHistoryTable[indexPieceTo(movePiece(move), moveTarget(move))]; - moveCount++; - Score score = -quiescence(-beta, -alpha, ss+1); - undo(undoer, move); - if (score > bestScore) - { - bestScore = score; - if (score > alpha) - { - bestMove = move; - if (score >= beta) - break; - alpha = score; - } - // Obsidian ml pruning idea - if (bestScore >= -KNOWNWIN) { - if (pos.checkers && okToReduce(move)) break; - } - } - } - else - undo(undoer, move); - } - - if (moveCount == 0 && inCheck) - return matedIn(ply); - - U8 ttStoreFlag = bestScore >= beta ? hashLOWER : hashUPPER; // No exact bounds in qsearch - writeTT(pos.hashKey, bestScore, rawEval, 0, ttStoreFlag, bestMove, ply, PVNode, ttPv, age); - - return bestScore; -} - -#define ASPIRATIONWINDOW 25 -void Game::startSearch(bool ageTT = true) -{ - // Set SE counters to 0 - seCandidates = 0; - seActivations = 0; - avgDist = 0; - SStack stack[4 + maxPly + 1]; // 4 is the max ply that we look back, 1 is the max ply that we look forward (for now it is actually -2, but hopefully we extend conthist to -4) - SStack* ss = stack + 4; - - for (int i = -4; i < maxPly + 1; i++) (ss+i)->wipe(); - - Score delta = ASPIRATIONWINDOW; - nodes = 0ULL; - stopped = false; - ply = 0; - seldepth = 0; - nmpPlies = 0; - - std::cin.clear(); - - lastScore = 0; - - startTime = getTime64(); - U64 optim = 0xffffffffffffffffULL; -#define UCILATENCYMS 20 - switch (searchMode) { - case 0: // Infinite search - depth = maxPly - 1; // Avoid overflow - case 1: // Fixed depth - optim = moveTime = 0xffffffffffffffffULL; - break; - case 2: // Time control - moveTime = getTime64(); - U64 totalTime; - if (pos.side == WHITE) totalTime = (U64)(wtime * timeTmA() / RESOLUTION) + winc * timeTmB() / RESOLUTION; - else totalTime = (U64)(btime * timeTmA() / RESOLUTION) + binc * timeTmB() / RESOLUTION; - totalTime -= UCILATENCYMS; - optim = totalTime * timeTmOptimScale() / 1000; - - moveTime += totalTime; - depth = maxPly - 1; - break; - case 3: - moveTime -= UCILATENCYMS; - optim = moveTime; - depth = maxPly - 1; - break; - } - - - double nodesTmScale = 1.0; - - // Clear nodePerMoveTable - memset(nodesPerMoveTable, 0, sizeof(nodesPerMoveTable)); - - // Clear pv len and pv table - memset(pvLen, 0, sizeof(pvLen)); - memset(pvTable, 0, sizeof(pvTable)); - - Score alpha = noScore; - Score beta = infinity; - if (ageTT) age = (age + 1) & 31; - - // Always compute a depth 1 search - rootDelta = 2 * infinity; - currSearch = 1; - - Score score = search(noScore, infinity, 1, false, ss); - Move bestMove = pvTable[0][0]; - - std::cout << "info depth 1 score cp " << score << " nodes " << nodes << " moves "; - printMove(bestMove); - std::cout << std::endl; - - depth = std::min(depth, Depth(maxPly - 3)); - if (depth < 0) - depth = maxPly - 3; - if (stopped) - goto bmove; - - for (Depth searchDepth = 2; (searchDepth <= depth) && searchDepth >= 2 && !stopped; searchDepth++) - { - currSearch = searchDepth; - delta = ASPIRATIONWINDOW; - if (currSearch >= 4) - { - alpha = std::max(S32(noScore), score - delta); - beta = std::min(S32(infinity), score + delta); - - } - // Calculate optim base - while (true) - { - seldepth = 0; // Reset seldepth - ply = 0; - S64 locNodes = nodes; // Save nodes for nps calculation - U64 timer1 = getTime64(); // Save time for nps calculation - // Clear the first sstack entry - ss->wipe(); - score = search(alpha, beta, currSearch, false, ss); // Search at depth currSearch - if (stopped) - goto bmove; - bestMove = pvTable[0][0]; - U64 timer2 = getTime64(); - - if (score <= alpha) - { - beta = (alpha + beta) / 2; - alpha = std::max(S32(noScore), score - delta); - - if (score < -mateValue && score > -mateScore) - std::cout << std::dec << "info depth " << (int)searchDepth << " score mate " << -(mateScore + score + 2) / 2 << " lowerbound nodes " << nodes << " pv "; - else if (score > mateValue && score < mateScore) - std::cout << std::dec << "info depth " << (int)searchDepth << " score mate " << (mateScore + 1 - score) / 2 << " lowerbound nodes " << nodes << " pv "; - else - std::cout << std::dec << "info depth " << (int)searchDepth << " score cp " << (score >> 1) << " lowerbound nodes " << nodes << " pv "; - printMove(pvTable[0][0]); - std::cout << " nps " << (((nodes - locNodes) * 1000) / (timer2 - timer1 + 1)) << std::endl; - delta *= 1.44; - currSearch = searchDepth; - } - else if (score >= beta) - { - beta = std::min(S32(infinity), score + delta); - if (score < -mateValue && score > -mateScore) - std::cout << std::dec << "info depth " << (int)searchDepth << " score mate " << -(mateScore + score + 2) / 2 << " upperbound nodes " << nodes << " pv "; - else if (score > mateValue && score < mateScore) - std::cout << std::dec << "info depth " << (int)searchDepth << " score mate " << (mateScore + 1 - score) / 2 << " upperbound nodes " << nodes << " pv "; - else - std::cout << std::dec << "info depth " << (int)searchDepth << " score cp " << (score >> 1) << " upperbound nodes " << nodes << " pv "; - printMove(pvTable[0][0]); - std::cout << " nps " << (((nodes - locNodes) * 1000) / (timer2 - timer1 + 1)) << std::endl; - delta *= 1.44; - currSearch = std::max(4,std::max(searchDepth - 5, currSearch - 1)); - } - else - { - if (score < -mateValue && score > -mateScore) - std::cout << std::dec << "info score mate " << -(mateScore + score + 2) / 2 << " depth " << (int)searchDepth << " seldepth " << (int)seldepth << " nodes " << nodes << " hashfull " << hashfull(age) << " pv "; - else if (score > mateValue && score < mateScore) - std::cout << std::dec << "info score mate " << (mateScore + 1 - score) / 2 << " depth " << (int)searchDepth << " seldepth " << (int)seldepth << " nodes " << nodes << " hashfull " << hashfull(age) << " pv "; - else - std::cout << std::dec << "info score cp " << (score >> 1) << " depth " << (int)searchDepth << " seldepth " << (int)seldepth << " nodes " << nodes << " hashfull " << hashfull(age) << " pv "; - - for (int i = 0; i < pvLen[0]; i++) - { - printMove(pvTable[0][i]); - std::cout << " "; - } - std::cout << " nps " << (((nodes - locNodes) * 1000) / (timer2 - timer1 + 1)) << std::endl; - break; - } - } - if (currSearch >= 6){ - // 1.242 felt cute, maybe it gains - nodesTmScale = ((S64)nodesTmMax() - ((double)nodesPerMoveTable[indexFromTo(moveSource(bestMove), moveTarget(bestMove))] / (double)nodes) * (S64)nodesTmMul()) / RESOLUTION; - } - // Check optim time quit - if (getTime64() > startTime + optim * nodesTmScale) break; - } - -bmove: - // Report final search info (6307869) - std::cout << "info nodes " << nodes << std::endl; - std::cout << "bestmove "; - printMove(bestMove); - std::cout << std::endl; -} \ No newline at end of file diff --git a/src/tables.cpp b/src/tables.cpp deleted file mode 100644 index 04f194d..0000000 --- a/src/tables.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include "tables.h" -#include "evaluation.h" -#include "types.h" -#include "random.h" -#include "BBmacros.h" -#include "movegen.h" -#include "zobrist.h" -#include "tt.h" -#include - -// bishop attack masks -BitBoard bishopMasks[64]; -// rook attack masks -BitBoard rookMasks[64]; -// bishop attacks table -BitBoard bishopAttacks[64][512]; -// rook attacks table -BitBoard rookAttacks[64][4096]; - -// tropism -int distBonus[64][64]; -int qkdist[64][64]; -int rkdist[64][64]; -int nkdist[64][64]; -int bkdist[64][64]; -int kbdist[64][64]; -// mhDist -U8 manhattanDistance[64][64]; -// cbyDist -U8 chebyshevDistance[64][64]; -// centerDistance -U8 centerDistance[64]; -// squaresBetween -BitBoard squaresBetween[64][64]; // TODO: squaresBetween doesn't quite work... - -// pv table and pv length -Move pvTable[maxPly][maxPly] = { {0} }; -Ply pvLen[maxPly] = { 0 }; -// Repetition Table -HashKey repetitionTable[512] = { 0ULL }; - -BitBoard squaresToRight[64]; -BitBoard squaresToLeft[64]; -BitBoard passedPawnMask[2][64]; -BitBoard isolatedPawnMask[64]; -BitBoard backwardPawnMask[2][64]; -BitBoard phalanx[64]; -BitBoard outerRing[64]; -BitBoard fiveSquare[64]; // The 5x5 square -BitBoard kingShelter[2][64]; // The king shelter -BitBoard kingFlank[2][8]; - -// Precomputed sigmoid king safety tables -std::array kingSafetyMgTable; -std::array kingSafetyEgTable; - -// Helper function to compute the King Safety for Middlegame -static inline int computeKingSafetyMg(double x) { - double f = x / 480.0; - f = KSBMG * f + KSCMG; - f = KSCALEMG / (std::exp(-f) + 1.0); - return static_cast(f); -} - -// Helper function to compute the King Safety for Endgame -static inline int computeKingSafetyEg(double x) { - double f = x / 480.0; - f = KSBEG * f + KSCEG; - f = KSCALEEG / (std::exp(-f) + 1.0); - return static_cast(f); -} - -// Function to initialize the precomputed tables -void initializeKingSafetyTables() { - for (int i = 0; i < KSTABLESIZE; ++i) { - double x = MIN_X + i * (MAX_X - MIN_X) / (KSTABLESIZE - 1); - kingSafetyMgTable[i] = computeKingSafetyMg(x); - kingSafetyEgTable[i] = computeKingSafetyEg(x); - } -} - -// The LMR reduction table -S32 reductionTable[2][64][64] = { { {0} } }; -S32 lmpMargin[128][2] = { {0} }; -/** - * @brief The initLMRTable function initializes the LMR reduction table - */ -void initLMRTable(){ - for (int i = 0; i < 64; i++){ - reductionTable[0][i][0] = reductionTable[1][i][0] = reductionTable[0][0][i] = reductionTable[1][0][i] = 0; - } - // std::cout << "Initializing lmrlmp tables" << std::endl; - for (int depth = 1; depth < 64; depth++) { - for (int move = 1; move < 64; move++) { - reductionTable[0][depth][move] = std::max(0, - int( - lmrA0() * - log(depth * (double)lmrDepthValue() / RESOLUTION) * - log(move * (double)lmrMoveValue() / RESOLUTION) + - lmrC0() - ) - ); - reductionTable[1][depth][move] = std::max(0, - int( - lmrA1() * - log(depth * (double)lmrDepthValue() / RESOLUTION) * - log(move * (double)lmrMoveValue() / RESOLUTION) + - lmrC1() - ) - ); - } - } - // Init lmpMargin - for (int depth = 0; depth < 128; depth++) { - for (int improving = 0; improving < 2; improving++) { - lmpMargin[depth][0] = (lmpC0() + lmpA0() * depth * depth) / RESOLUTION; // 1.5 + 0.5 * std::pow(depth, 2.0); // Not improving - lmpMargin[depth][1] = (lmpC1() + lmpA1() * depth * depth) / RESOLUTION; // 3.0 + 1.0 * std::pow(depth, 2.0); // improving - } - } -} - -/** - * @brief The initEvalTables function initializes the evaluation tables. - */ -void initEvalTables() { - // Initialize king safety tables - initializeKingSafetyTables(); - //BitBoard squaresToLeft[64]; - for (Square square = a8; square < noSquare; square++) { - BitBoard res = ranks(rankOf(square)); - for (Square clear = square; clear < noSquare; clear++) clearBit(res, clear); - squaresToLeft[square] = res; - } - //BitBoard squaresToRight[64]; - for (Square square = 0; square < noSquare; square++) { - BitBoard res = ranks(rankOf(square)); - res ^= (squareBB(square) | squaresToLeft[square]); - squaresToRight[square] = res; - } - - //BitBoard isolatedPawnMask[64] - for (Square square = 0; square < 64; square++) { - BitBoard res = 0; - res |= (fileOf(square) >= 1 ? files(fileOf(square) - 1) : 0); - res |= (fileOf(square) <= 6 ? files(fileOf(square) + 1) : 0); - //res &= (~squareBB(square)); - isolatedPawnMask[square] = res; - } - - //BitBoard passedPawnMask[2][64]; - for (Square square = a8; square < noSquare; square++) { - - BitBoard res = squaresAhead(square) | ((fileOf(square) != 7) ? squaresAhead(square + 1) : 0) | ((fileOf(square) != 0) ? squaresAhead(square - 1) : 0); - passedPawnMask[WHITE][square] = res; - - res = squaresBehind(square) | ((fileOf(square) != 7) ? squaresBehind(square+1) : 0 ) | ((fileOf(square) != 0) ? squaresBehind(square - 1) : 0 ); - passedPawnMask[BLACK][square] = res; - - } - - //BitBoard backwardPawnMask[2][64]; - for (int side = 0; side < 2; side++) { - for (Square square = 0; square < 64; square++){ - BitBoard res = passedPawnMask[side^1][square]; - res &= notFile(fileOf(square)); - res &= notRank(0); - res &= notRank(7); - if (fileOf(square) > 0) res |= squareBB(square - 1); - if (fileOf(square) < 7) res |= squareBB(square + 1); - backwardPawnMask[side][square] = res; - } - } - - //BitBoard phalanx[64] - for (Square square = 0; square < 64; square++){ - phalanx[square] = 0; - if (fileOf(square) > 0) phalanx[square] |= squareBB(square - 1); - if (fileOf(square) < 7) phalanx[square] |= squareBB(square + 1); - } - - // mha, cby distance - for (Square square1 = a8; square1 < noSquare; square1++){ - for (Square square2 = a8; square2 < noSquare; square2++){ - int file1, file2, rank1, rank2; - int rankDistance, fileDistance; - file1 = square1 & 7; - file2 = square2 & 7; - rank1 = square1 >> 3; - rank2 = square2 >> 3; - rankDistance = abs(rank2 - rank1); - fileDistance = abs(file2 - file1); - manhattanDistance[square1][square2] = rankDistance + fileDistance; - chebyshevDistance[square1][square2] = std::max(rankDistance, fileDistance); - } - int file, rank; - file = square1 & 7; - rank = square1 >> 3; - file ^= (file - 4) >> 8; - rank ^= (rank - 4) >> 8; - centerDistance[square1] = (file + rank) & 7; - } - - // squaresBetween[64][64] - - for (Square sq1 = a8; sq1 < noSquare; sq1++) { - int rank = rankOf(sq1); - int file = fileOf(sq1); - // We generate the squares on left - { - BitBoard between = 0ULL; - for (int i = file - 1; i >= 0; i--) { - squaresBetween[sq1][makeSquare(rank,i)] = between; - between |= squareBB(makeSquare(rank, i)); - } - } - // We generate the squares on right - { - BitBoard between = 0ULL; - for (int i = file + 1; i < 8; i++) { - squaresBetween[sq1][makeSquare(rank,i)] = between; - between |= squareBB(makeSquare(rank, i)); - } - } - // We generate the squares on top - { - BitBoard between = 0ULL; - for (int i = rank - 1; i >= 0; i--) { - squaresBetween[sq1][makeSquare(i,file)] = between; - between |= squareBB(makeSquare(i, file)); - } - } - // We generate the squares on bottom - { - BitBoard between = 0ULL; - for (int i = rank + 1; i < 8; i++) { - squaresBetween[sq1][makeSquare(i,file)] = between; - between |= squareBB(makeSquare(i, file)); - } - } - // NW diagonal: - { - BitBoard between = 0ULL; - for (int i = rank - 1, j = file - 1; i >= 0 && j >= 0; i--, j--) { - squaresBetween[sq1][makeSquare(i,j)] = between; - between |= squareBB(makeSquare(i, j)); - } - } - // NE diagonal: - { - BitBoard between = 0ULL; - for (int i = rank - 1, j = file + 1; i >= 0 && j < 8; i--, j++) { - squaresBetween[sq1][makeSquare(i,j)] = between; - between |= squareBB(makeSquare(i, j)); - } - } - // SW diagonal: - { - BitBoard between = 0ULL; - for (int i = rank + 1, j = file - 1; i < 8 && j >= 0; i++, j--) { - squaresBetween[sq1][makeSquare(i,j)] = between; - between |= squareBB(makeSquare(i, j)); - } - } - // SE diagonal: - { - BitBoard between = 0ULL; - for (int i = rank + 1, j = file + 1; i < 8 && j < 8; i++, j++) { - squaresBetween[sq1][makeSquare(i,j)] = between; - between |= squareBB(makeSquare(i, j)); - } - } - - // Outer ring - { - BitBoard ring = 0ULL; - for (int i = -1; i < 2; i++){ - for (int j = -1; j < 2; j++){ - if (rank + i < 0 || rank + i > 7 || file + j < 0 || file + j > 7) continue; - ring |= kingAttacks[makeSquare(rank + i, file + j)]; - } - } - fiveSquare[sq1] = ring; - ring &= ~(kingAttacks[sq1] | squareBB(sq1)); - - outerRing[sq1] = ring; - } - - // King shelter - { - BitBoard sq = squareBB(sq1); - kingShelter[WHITE][sq1] = north(sq) | ne(sq) | nw(sq); - kingShelter[BLACK][sq1] = south(sq) | se(sq) | sw(sq); - } - } - // King flank - { - BitBoard flank = squareBB(a8) | squareBB(b8) | squareBB(c8) | squareBB(d8); - flank |= south(flank); - flank |= south(south(flank)); - flank |= south(flank); - kingFlank[BLACK][0] = kingFlank[BLACK][1] = kingFlank[BLACK][2] = flank; - flank = east(east(flank)); - kingFlank[BLACK][3] = kingFlank[BLACK][4] = flank; - flank = east(east(flank)); - kingFlank[BLACK][5] = kingFlank[BLACK][6] = flank; - } - // King flank - { - BitBoard flank = squareBB(a1) | squareBB(b1) | squareBB(c1) | squareBB(d1); - flank |= north(flank); - flank |= north(north(flank)); - flank |= north(flank); - kingFlank[WHITE][0] = kingFlank[WHITE][1] = kingFlank[WHITE][2] = flank; - flank = east(east(flank)); - kingFlank[WHITE][3] = kingFlank[WHITE][4] = flank; - flank = east(east(flank)); - kingFlank[WHITE][5] = kingFlank[WHITE][6] = flank; - } -} - -void initTropism(){ - int diag_nw[64] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 1, 2, 3, 4, 5, 6, 7, 8, - 2, 3, 4, 5, 6, 7, 8, 9, - 3, 4, 5, 6, 7, 8, 9,10, - 4, 5, 6, 7, 8, 9,10,11, - 5, 6, 7, 8, 9,10,11,12, - 6, 7, 8, 9,10,11,12,13, - 7, 8, 9,10,11,12,13,14 - }; - - int diag_ne[64] = { - 7, 6, 5, 4, 3, 2, 1, 0, - 8, 7, 6, 5, 4, 3, 2, 1, - 9, 8, 7, 6, 5, 4, 3, 2, - 10, 9, 8, 7, 6, 5, 4, 3, - 11,10, 9, 8, 7, 6, 5, 4, - 12,11,10, 9, 8, 7, 6, 5, - 13,12,11,10, 9, 8, 7, 6, - 14,13,12,11,10, 9, 8, 7 - }; - - int bonus_dia_distance[15] = { 5, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - /* initializes the table of distances between squares */ - int i, j; - - /* basic distance table used to generate separate tables for pieces */ - for (i = 0; i < 64; ++i) { - for (j = 0; j < 64; ++j) { - distBonus[i][j] = 14 - (abs(fileOf(i) - fileOf(j)) + abs(rankOf(i) - rankOf(j))); - - qkdist[i][j] = (distBonus[i][j] * 5) / 2; - rkdist[i][j] = distBonus[i][j] / 2; - nkdist[i][j] = distBonus[i][j]; - /* bk_dist[i][j] takes into account the numbers of the diagonals */ - bkdist[i][j] = distBonus[i][j] / 2; - kbdist[i][j] = bonus_dia_distance[abs(diag_ne[i] - diag_ne[j])]; - kbdist[i][j] += bonus_dia_distance[abs(diag_nw[i] - diag_nw[j])]; - } - } -} - - - -/** - * @brief The initAll function initializes the tables. - * @note THis is called at the beginning of the program. - */ -void initAll(){ - initLMRTable(); - initEvalTables(); - initTropism(); - //initMagic(); - initSliderAttacks(true); - initSliderAttacks(false); - initHashKeys(); - initTables(); - initTT(); -} \ No newline at end of file diff --git a/src/tables.h b/src/tables.h deleted file mode 100644 index 27b430b..0000000 --- a/src/tables.h +++ /dev/null @@ -1,177 +0,0 @@ -#pragma once - -#include "types.h" -#include "constants.h" -#include -#define RESOLUTION 1000 - -//tropism -extern int distBonus[64][64]; -extern int qkdist[64][64]; -extern int rkdist[64][64]; -extern int nkdist[64][64]; -extern int bkdist[64][64]; -extern int kbdist[64][64]; -// mhDist -extern U8 manhattanDistance[64][64]; -// cbyDist -extern U8 chebyshevDistance[64][64]; -// kingshelter -extern BitBoard kingShelter[2][64]; -// flank -extern BitBoard kingFlank[2][8]; - -// centerDistance -extern U8 centerDistance[64]; -// squaresbetween -extern BitBoard squaresBetween[64][64]; -// pv table and pv length -extern Move pvTable[maxPly][maxPly]; -extern Ply pvLen[maxPly]; -// Repetition Table -extern HashKey repetitionTable[512]; -// The LMR reduction table -extern S32 reductionTable[2][64][64]; -extern S32 lmpMargin[128][2]; - - -constexpr S32 KSTABLESIZE = 256; -constexpr S32 MIN_X = -4096; -constexpr S32 MAX_X = 4096; -extern std::array kingSafetyMgTable; -extern std::array kingSafetyEgTable; - - -/** - * @brief The initLMRTable function initializes the LMR reduction table - */ -void initLMRTable(); - -constexpr S8 colorCornerDistance[2][64] = { - { - +9, +4, -1, +0, -4, -6, -8, -9, - +4, -1, -3, -7, -7, -8, -9, -8, - +1, -3, -7, -7, -8, -9, -8, -6, - +0, -7, -7, -10, -10, -8, -7, -4, - -4, -7, -8, -10, -10, -7, -7, +0, - -6, -8, -9, -8, -7, -7, -3, +1, - -8, -9, -8, -7, -7, -3, -1, +4, - -9, -8, -6, -4, +0, +1, +4, +9, - }, - { - -9, -8, -6, -4, +0, +1, +4, +9, - -8, -9, -8, -7, -7, -3, -1, +4, - -6, -8, -9, -8, -7, -7, -3, +1, - -4, -7, -8, -10, -10, -7, -7, +0, - +0, -7, -7, -10, -10, -8, -7, -4, - +1, -3, -7, -7, -8, -9, -8, -6, - +4, -1, -3, -7, -7, -8, -9, -8, - +9, +4, -1, +0, -4, -6, -8, -9, - } -}; - -constexpr BitBoard boardSide[2] = { - 1085102592571150095ULL, - 17361641481138401520ULL -}; - -constexpr U64 MvvLva[12][12] = { - // Aggressor - Victim - {105, 205, 305, 405, 505, 605, 105, 205, 305, 405, 505, 605}, - {104, 204, 304, 404, 504, 604, 104, 204, 304, 404, 504, 604}, - {103, 203, 303, 403, 503, 603, 103, 203, 303, 403, 503, 603}, - {102, 202, 302, 402, 502, 602, 102, 202, 302, 402, 502, 602}, - {101, 201, 301, 401, 501, 601, 101, 201, 301, 401, 501, 601}, - {100, 200, 300, 400, 500, 600, 100, 200, 300, 400, 500, 600}, - - {105, 205, 305, 405, 505, 605, 105, 205, 305, 405, 505, 605}, - {104, 204, 304, 404, 504, 604, 104, 204, 304, 404, 504, 604}, - {103, 203, 303, 403, 503, 603, 103, 203, 303, 403, 503, 603}, - {102, 202, 302, 402, 502, 602, 102, 202, 302, 402, 502, 602}, - {101, 201, 301, 401, 501, 601, 101, 201, 301, 401, 501, 601}, - {100, 200, 300, 400, 500, 600, 100, 200, 300, 400, 500, 600}, -}; - -constexpr U32 promotionBonus[12] = { - 0, 70000, 80000, 90000, 100000, 0, 0, 70000, 80000, 90000, 100000, 0}; - -// Thanks to loki for the following 2 tables! -// Indexed by 7 + rank - file -// The diagonals start at the h1-h1 and end in the a8-a8 -constexpr BitBoard diagonalMasks[15] = { - 128ULL, - 32832ULL, - 8405024ULL, - 2151686160ULL, - 550831656968ULL, - 141012904183812ULL, - 36099303471055874ULL, - 9241421688590303745ULL, - 4620710844295151872ULL, - 2310355422147575808ULL, - 1155177711073755136ULL, - 577588855528488960ULL, - 288794425616760832ULL, - 144396663052566528ULL, - 72057594037927936ULL -}; - -// Indexed by: rank + file -// Anti-diagonals go from a1-a1 to h8-h8 -constexpr BitBoard antidiagonalMasks[15] = { - 1ULL, - 258ULL, - 66052ULL, - 16909320ULL, - 4328785936ULL, - 1108169199648ULL, - 283691315109952ULL, - 72624976668147840ULL, - 145249953336295424ULL, - 290499906672525312ULL, - 580999813328273408ULL, - 1161999622361579520ULL, - 2323998145211531264ULL, - 4647714815446351872ULL, - 9223372036854775808ULL -}; - -extern const U64 MvvLva[12][12]; - -extern const U32 promotionBonus[12]; - -extern BitBoard squaresToRight[64]; -extern BitBoard squaresToLeft[64]; -extern BitBoard passedPawnMask[2][64]; -extern BitBoard isolatedPawnMask[64]; -extern BitBoard backwardPawnMask[2][64]; -extern BitBoard phalanx[64]; -const PScore kingSafety[64] = { // TODO: Replace with PScore tuned values - S( 10 , 15 ), S( 12 , 17 ), S( 13 , 19 ), S( 15 , 22 ), S( 17 , 25 ), S( 19 , 28 ), S( 21 , 31 ), S( 24 , 35 ), - S( 27 , 40 ), S( 31 , 45 ), S( 34 , 51 ), S( 39 , 57 ), S( 43 , 64 ), S( 49 , 72 ), S( 55 , 80 ), S( 61 , 90 ), - S( 68 , 100 ), S( 76 , 112 ), S( 85 , 125 ), S( 94 , 138 ), S( 105 , 153 ), S( 116 , 170 ), S( 128 , 187 ), S( 140 , 206 ), - S( 154 , 226 ), S( 169 , 247 ), S( 184 , 270 ), S( 200 , 293 ), S( 216 , 318 ), S( 233 , 343 ), S( 251 , 368 ), S( 269 , 394 ), - S( 286 , 420 ), S( 304 , 447 ), S( 322 , 473 ), S( 340 , 498 ), S( 357 , 523 ), S( 373 , 548 ), S( 389 , 571 ), S( 404 , 594 ), - S( 419 , 615 ), S( 433 , 635 ), S( 445 , 654 ), S( 457 , 671 ), S( 468 , 688 ), S( 479 , 703 ), S( 488 , 716 ), S( 497 , 729 ), - S( 505 , 741 ), S( 512 , 751 ), S( 518 , 761 ), S( 524 , 769 ), S( 530 , 777 ), S( 534 , 784 ), S( 539 , 790 ), S( 542 , 796 ), - S( 546 , 801 ), S( 549 , 806 ), S( 552 , 810 ), S( 554 , 813 ), S( 556 , 816 ), S( 558 , 819 ), S( 560 , 822 ), S( 561 , 824 ), -}; - -constexpr Score connectedSeed[] = { 0, 5, 6, 9, 23, 37, 67 }; -constexpr Score blockBonusMg[] = { 0, -9, -2 }; -constexpr Score blockBonusEg[] = { 0, -3, 3 }; - -extern BitBoard outerRing[64]; // The ring of squares in a centered 5x5 square -extern BitBoard fiveSquare[64]; // The 5x5 square -extern BitBoard kingShelter[2][64]; // The king shelter - -/** - * @brief The initEvalTables function initializes the evaluation tables - */ -void initEvalTables(); - -/** - * @brief The initAll function initializes the tables. - * @note THis is called at the beginning of the program. - */ -void initAll(); diff --git a/src/tt.cpp b/src/tt.cpp deleted file mode 100644 index 321f42e..0000000 --- a/src/tt.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "tt.h" -#include "constants.h" -#include "move.h" -#include "uci.h" -#include - -ttEntry::ttEntry(HashKey h, U16 b, Depth d, U8 f, Score s) { - hashKey = h; - bestMove = b; - depth = d; - agePvFlag = f; - score = s; -} - -ttEntry::ttEntry() { - hashKey = 0; - bestMove = 0; - depth = 0; - agePvFlag = hashNONE; - score = noScore; - eval = noScore; -} - -// Transposition table and evaluation hash table -std::vector tt; - -void initTT(){ - resizeTT(hashSize); -} - -ttEntry* probeTT(HashKey key) { - ttEntry *entry = &tt[hashEntryFor(key)]; - // Iterate through the entries. - if (entry->hashKey == key) { - // entry->flags &= ~hashOLD; - return entry; - } - return nullptr; -} - -static inline bool sameAge(const U8 age, const U8 bound){ - return age == (bound & 31); -} - -static inline U8 buildAgePvBound(const U8 age, const U8 pv, const U8 bound){ - return age | (pv << 5) | bound; -} - -void writeTT(HashKey key, Score score, Score staticEval, Depth depth, U8 bound, Move move, Ply ply, bool isPv, bool wasPv, U8 age) { - - ttEntry *entry = &tt[hashEntryFor(key)]; - if (((bound & hashEXACT) > (entry->agePvFlag & hashEXACT)) || !sameAge(age, entry->agePvFlag) || depth + 2 * isPv + 3 * (entry->hashKey != key) >= entry->depth) { - score -= ply * (score < -mateValue); - score += ply * (score > mateValue); - - // Iterate through the entries. - entry->score = score; - entry->eval = staticEval; - entry->depth = depth; - entry->agePvFlag = buildAgePvBound(age, wasPv, bound); - entry->bestMove = move ? packMove(move) : (entry->hashKey == key) ? entry->bestMove : 0; // pack to 2 bytes, if we don't have a move, we don't want to overwrite the old move if usable - entry->hashKey = key; - return; - } -} - -U16 hashfull(U8 age) { - U16 cnt = 0; - for (int i = 0; i < 1000; i++) if (tt[i].hashKey && (sameAge(age, tt[i].agePvFlag))) cnt++; - return cnt; -} \ No newline at end of file diff --git a/src/tt.h b/src/tt.h deleted file mode 100644 index 14c61c4..0000000 --- a/src/tt.h +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once -#include "types.h" -#include "constants.h" -#include - -// Table sizes (TODO: Make these configurable at runtime) -constexpr U64 ttEntryCount = 1048576; // 2^20 -constexpr U64 ttBucketSize = 4; // 2^2 -constexpr U64 ttBucketCount = ttEntryCount / ttBucketSize; // 2^18 - -// The enum of hashFlags -enum HashFlag -{ - hashNONE = 0, - hashUPPER = 0b01000000, - hashLOWER = 0b10000000, - hashEXACT = 0b11000000, - hashPVMove = 0b00100000 -}; - -#ifdef _MSC_VER -__declspec(align(16)) struct ttEntry { - ttEntry(HashKey h, U16 b, Depth d, U8 f, Score s); - ttEntry(); - HashKey hashKey; // 8 - PackedMove bestMove; // 2 - Depth depth; // 1 - U8 flags = hashINVALID; // 1 - Score score = noScore; // 2 - Score eval = noScore; // 2 -}; - -__declspec(align(64))struct ttBucket { - ttEntry entries[ttBucketSize]; - ttBucket(){ - for (U64 i = 0; i < ttBucketSize; i++){ - entries[i] = ttEntry(0, 0, 0, hashINVALID, 0); - entries[i].eval = noScore; - } - } -}; -#elif __GNUC__ -struct ttEntry { - ttEntry(HashKey h, U16 b, Depth d, U8 f, Score s); - ttEntry(); - HashKey hashKey; // 8 - PackedMove bestMove; // 2 - Depth depth; // 1 - U8 agePvFlag = hashNONE; // 1 - Score score = noScore; // 2 - Score eval = noScore; // 2 -} __attribute__((aligned(16))); - -struct ttBucket { - ttEntry entries[ttBucketSize]; - ttBucket(){ - for (U64 i = 0; i < ttBucketSize; i++){ - entries[i] = ttEntry(0, 0, 0, hashNONE, 0); - entries[i].eval = noScore; - } - } -} __attribute__((aligned(64))); -#else -// TODO: Add support for other compilers -#error "Compiler not supported" -#endif - - - -// Transposition table and evaluation hash table -extern std::vector tt; - -inline U64 hashEntryFor(HashKey key) { - return static_cast( - ( - (static_cast(key) * static_cast(tt.size())) >> 64 - ) - ); -} - -static inline void resizeTT(U64 mbSize){ - // calculate the number of entries - U64 ttEntryCount = 1024 * 1024 * mbSize / sizeof(ttEntry); - // allocate the memory on the tt vector - tt.resize(ttEntryCount); - // clear the memory - for (ttEntry &e : tt) e = ttEntry(); -} - -/** - * @brief The initTT function initializes the transposition table and evaluation cache. - * @note The size is not configurable at runtime yet. - */ -void initTT(); - -/** - * @brief The probeTT function probes the transposition table. It checks if the entry exists and if it is valid. - * @param key The key. - * @return The entry, or nullptr if it does not exist. - */ -ttEntry *probeTT(HashKey key); - -/** - * @brief The writeTT function writes the entry to the transposition table. - * @param key The key. - * @param score The score. - * @param depth The depth. - * @param bound The flags. - * @param move The move. - * @param ply The ply. - * @param isPv The isPv flag. - * @param wasPv The wasPv flag. - * @param age The age gen - */ -void writeTT(HashKey key, Score score, Score staticEval, Depth depth, U8 bound, Move move, Ply ply, bool isPv, bool wasPv, U8 age); - -U16 hashfull(U8 age); \ No newline at end of file diff --git a/src/types.h b/src/types.h deleted file mode 100644 index 095d302d..0000000 --- a/src/types.h +++ /dev/null @@ -1,121 +0,0 @@ -#pragma once -#include -#include -#include -#include - -typedef unsigned long long U64; -typedef signed long long S64; -typedef unsigned int U32; -typedef signed int S32; -typedef unsigned short U16; -typedef signed short S16; -typedef unsigned char U8; -typedef signed char S8; -typedef signed char Depth; -typedef signed short Ply; -typedef __uint128_t U128; - -// The BitBoard type is a typedef for U64. -typedef unsigned long long BitBoard; -// The ScoredMove type is a typedef for U64. -typedef unsigned long long ScoredMove; -// The HashKey type is a typedef for U64 -typedef unsigned long long HashKey; -// The Move type is a typedef for U32. -typedef unsigned int Move; -// The packedMove type is a typedef for U16. -typedef unsigned short PackedMove; -// The Score type is a typedef for S16. -typedef signed short Score; -// The Square type is a typedef for U8. -typedef unsigned char Square; -// The Piece type is a typedef for U8. -typedef unsigned char Piece; - - -// ( I LOVED LIFTING SF CODE, (apparently it was UB), NOW POLARIS IS MY NEW BEST FRIEND ) -class PScore { - private: - S32 m_score; - explicit constexpr PScore(S32 score) : m_score{score} {} - - public: - constexpr PScore() : m_score{} {} - - constexpr PScore(Score midgame, Score endgame) - : m_score{static_cast(static_cast(endgame) << 16) + midgame} - { - assert(std::numeric_limits::min() <= midgame && std::numeric_limits::max() >= midgame); - assert(std::numeric_limits::min() <= endgame && std::numeric_limits::max() >= endgame); - } - - [[nodiscard]] inline auto mg() const - { - const auto mg = static_cast(m_score); - - S16 v{}; - std::memcpy(&v, &mg, sizeof(mg)); - - return static_cast(v); - } - - [[nodiscard]] inline auto eg() const - { - const auto eg = static_cast(static_cast(m_score + 0x8000) >> 16); - - S16 v{}; - std::memcpy(&v, &eg, sizeof(eg)); - - return static_cast(v); - } - - [[nodiscard]] constexpr auto operator+(const PScore &other) const - { - return PScore{m_score + other.m_score}; - } - - constexpr auto operator+=(const PScore &other) -> auto & - { - m_score += other.m_score; - return *this; - } - - [[nodiscard]] constexpr auto operator-(const PScore &other) const - { - return PScore{m_score - other.m_score}; - } - - constexpr auto operator-=(const PScore &other) -> auto & - { - m_score -= other.m_score; - return *this; - } - - [[nodiscard]] constexpr auto operator*(S32 v) const - { - return PScore{m_score * v}; - } - - constexpr auto operator*=(S32 v) -> auto & - { - m_score *= v; - return *this; - } - - [[nodiscard]] constexpr auto operator-() const - { - return PScore{-m_score}; - } - - [[nodiscard]] constexpr bool operator==(const PScore &other) const = default; - - friend std::ostream& operator<< (std::ostream& stream, const PScore& score) { - stream << "(" << score.mg() << "\t" << score.eg() << ")"; - return stream; - } - -}; - -#define S(a,b) PScore((a),(b)) -#define SCORE_ZERO S(0,0) \ No newline at end of file diff --git a/src/uci.cpp b/src/uci.cpp deleted file mode 100644 index 0dd62b0..0000000 --- a/src/uci.cpp +++ /dev/null @@ -1,612 +0,0 @@ -#include "tt.h" -#include "types.h" -#include "movegen.h" -#include "tables.h" -#include "bench.h" -#include "evaluation.h" -#include "constants.h" -#include "uci.h" -#include "history.h" -#include -#include -#include - -bool quit = false; -int movesToGo = -1; // UCI parameter for the moves until the next time control. -int moveTime = -1; // UCI parameter for the time per move. -int increment = -1; // UCI parameter for the time increment. -U64 startTime = -1; // The time when the engine started calculating. -U64 stopTime = -1; // The time when the engine must stop calculating. -bool timeIsUp = false; // True if the time is up. -bool ponder = false; // True if the engine is pondering. -U8 timeSet = -1; // 0 for infinite, 1 for time per move, 2 for depth, 3 for normal play. -std::string hashDumpFile; // Additional opening hash file - -U32 hashSize = 64; // The size of the hash table in MB. - -void uciStr() { - std::cout << "id name " << "Perseus" << std::endl; - std::cout << "id author " << "G.M. Manduca" << std::endl; - std::cout << "option name Threads type spin default 1 min 1 max 1" << std::endl; - std::cout << "option name Hash type spin default 64 min 8 max 33554432" << std::endl; - - for(const TunableParam& param : tunableParams()) - std::cout << "option name " << param.name << " type spin default " << param.defaultValue << " min " << param.minValue << " max " << param.maxValue << std::endl; - - std::cout << "uciok" << std::endl; -} - -int executeCommand(Game* game, char* command) { - // Technically speaking, each possible command is present only once in the command, so we can look for the first character - // Command supported: - // - tt : Reads and reports the transposition table (if any) from the current position - // - isready : returns "readyok" if the engine is ready to accept commands - // - uci : returns engine info, followed by "uciok" - // - setoption name value (To implement) - // - ucinewgame : resets the engine to its initial state - // - position fen : sets the position to the given fen string - // - position startpos moves : sets the position to the given move list - // - go [depth / movetime / infinite] : starts the engine to search for the best move using the parameters specified in the command - // - stop : stops the engine from searching - // - fen : print the currently loaded fen - // - quit : exits the engine - // - print : prints the current position - // - eval : prints the static evaluation of the current position - // - divide : prints the perft results for the current position, divided for each move - // - movelist : wrapper for "divide 1" - // - exec : executes the given command ( no context is assumed, unless specified (this = game)) - // we will search for the first occurrence of a command - char* tuneStr = strstr((char*)command, "tunestr"); - char* ttt = strstr((char*)command, "tt"); - char* sanity = strstr((char*)command, "sanity"); - char* isReady = strstr((char*)command, "isready"); - char* uci = strstr((char*)command, "uci"); - char* setOption = strstr((char*)command, "setoption name"); - char* uciNewGame = strstr((char*)command, "ucinewgame"); - char* position = strstr((char*)command, "position"); - char* fen = strstr((char*)command, "fen"); - char* go = strstr((char*)command, "go"); - char* stop = strstr((char*)command, "stop"); - char* quit = strstr((char*)command, "quit"); - char* print = strstr((char*)command, "print"); - char* eval = strstr((char*)command, "eval"); - char* divide = strstr((char*)command, "divide"); - char* moveList = strstr((char*)command, "movelist"); - char* exec = strstr((char*)command, "exec"); - char* flip = strstr((char*)command, "flip"); - char* bench = strstr((char*)command, "bench"); - char* extract = strstr((char*)command, "extract"); - if (tuneStr){ - for(const TunableParam& param : tunableParams()) - std::cout << param.name << ", int, " << param.defaultValue << ", " << param.minValue << ", " << param.maxValue << ", " << param.cEnd << ", " << param.rEnd << std::endl; - return 0; - } - if (uciNewGame){ - initTT(); - game->reset(); - } - else if (uci) { - uciStr(); - return 0; - } - - if (isReady) - std::cout << "readyok" << std::endl; - - if (flip) { - game->pos.reflect(); - return 0; - } - - if (sanity) { - int cnt = 0; - for (U64 i = 0; i < ttEntryCount; i++) { - ttEntry entry = tt[i]; - if ((entry.eval != noScore) && (entry.eval != entry.score)) { - Depth depth; - Score score, eval; - HashKey hash; - PackedMove bestMove; - U8 flags; - - depth = entry.depth; - score = entry.score; - eval = entry.eval; - hash = entry.hashKey; - bestMove = entry.bestMove; - flags = entry.agePvFlag; - - std::cout << "TT for hashKey " << std::hex << hash << std::dec << ":\n"; - std::cout << "Score: " << score << "\t\tStatic eval: " << eval << "\n"; - std::cout << "Depth: " << (int)depth << "\n"; - std::cout << "BestMove: " << getMoveString(bestMove) << "\n"; - std::cout << "Flags:\n" << - (flags & hashUPPER ? "\thashUPPER\n" : "") << - (flags & hashLOWER ? "\thashLOWER\n" : "") << - (flags & hashEXACT ? "\thashEXACT\n" : "") << - (flags & hashNONE ? "\thashNONE\n" : "") << "\n\n"; - if (cnt++ >= 100) goto megabreak; - } - } - megabreak: - exit(-1); - } - - - - - if (setOption){ - setOptionCommand(command); - return 0; - } - - if (ttt) { - Position& pos = game->pos; - ttEntry* entry = probeTT(pos.hashKey); - if (!entry) { - std::cout << "No entry!\n"; - return 0; - } - Depth depth; - Score score, eval; - HashKey hash; - Move bestMove; - U8 flags; - - depth = entry->depth; - score = entry->score; - eval = entry->eval; - hash = entry->hashKey; - bestMove = entry->bestMove; - flags = entry->agePvFlag; - - std::cout << "TT for hashKey " << std::hex << pos.hashKey << " (" << hash << std::dec << ") :\n"; - std::cout << "Score: " << score << "\t\tStatic eval: " << eval << "\n"; - std::cout << "Depth: " << (int)depth << "\n"; - std::cout << "BestMove: " << getMoveString(bestMove) << "\n"; - std::cout << "Flags:\n" << - (flags & hashUPPER ? "\thashUPPER\n" : "") << - (flags & hashLOWER ? "\thashLOWER\n" : "") << - (flags & hashEXACT ? "\thashEXACT\n" : "") << - (flags & hashNONE ? "\thashNONE\n" : "") << "\n"; - std::cout << "Save age " << ((int)flags & 31) << " (current age is " << game->age << "\n"; - } - - if (position) positionCommand(game, command); - - if (fen) std::cout << game->pos.getFEN() << std::endl; - - if (go) goCommand(game, command); - - if (stop) game->stopped = true; - - if (quit) return 1; - - if (print) game->print(); - - if (eval) std::cout << "Static evaluation for current position (from side to move perspective): " << pestoEval(&(game->pos)) << std::endl; - - if (divide) { - std::cout << "Perft results for current position:" << std::endl; - game->divide(atoi(divide + 7)); - } - - if (moveList) game->divide(1); - - if (exec) execCommand(game, command); - - if (bench){ - char* args = bench + 5; - Depth depth; - depth = atoi(args); - if (depth == 0) depth = 12; - benchmark(depth); - } - - if (extract) { - // Get the filename - char* filename = extract + 8; - - // Convert the C-style string to a C++ std::string for easier manipulation - std::string inputFilename(filename); - std::string outputFilename; - - // Find the last '.' in the filename - size_t dotPos = inputFilename.find_last_of('.'); - - if (dotPos != std::string::npos) { - // If there's an extension, replace it with ".feat" - outputFilename = inputFilename.substr(0, dotPos) + ".feat"; - } else { - // If no extension, just add ".feat" - outputFilename = inputFilename + ".feat"; - } - - // Convert back to C-style string if needed for the function call - convertToFeatures(inputFilename.c_str(), outputFilename.c_str()); -} - - return 0; -} - -int setOptionCommand(char* command) { - // For now, we only have the stposHashDump command - // Get option name - char* optionNamec = command + 15; - // get string after - std::string optionName(optionNamec); - // find first space name - size_t space = optionName.find(" value "); - // split the arg - std::string arg = optionName.substr(space + 1 + 5 + 1); - // remove last characters from optionName - optionName.erase(space); - // Depending on optionName - - for (TunableParam& param : tunableParams()) { - if (param.name == optionName) { - int value = atoi(arg.c_str()); - if (value < param.minValue || value > param.maxValue) { - std::cout << "Invalid value for option " << optionName << "!\n"; - return 0; - } - param = value; - return 0; - } - } - - if (optionName == "stposHashDump") { - // Set hashDumpFile to arg - hashDumpFile = arg; - } - else if (optionName == "Threads"){ - // Nothing for now. TODO: update this when we add multithreading - } - else if (optionName == "Hash"){ - hashSize = atoi(arg.c_str()); - if (hashSize < 1) { - std::cout << "Invalid hash size!\n"; - return 0; - } - resizeTT(hashSize); - } - else if (optionName == "lmrDepthValue" - || optionName == "lmrMoveValue" - || optionName == "lmrA0" - || optionName == "lmrC0" - || optionName == "lmrA1" - || optionName == "lmrC1" - || optionName == "lmpA0" - || optionName == "lmpC0" - || optionName == "lmpA1" - || optionName == "lmpC1" - - ) initLMRTable(); - else { - std::cout << "Option " << optionName << " not recognized!\n"; - } - return 0; -} - -int positionCommand(Game *game, char* command){ - // the position command is composed by the following subcommands: - // - fen : sets the position to the specified fen string - // - startpos : sets the position to the starting position - // - trickypos : sets the position to the tricky position (debugging purposes) - // - moves : sets the position to the specified move list - - // we will search for the first occurrence of a command - - game->pos.wipe(); - - char* fen = strstr((char *)command, "fen"); - char* startposCMD = strstr((char *)command, "startpos"); - char* trickyposCMD = strstr((char *)command, "trickypos"); - char* moves = strstr((char *)command, "moves"); - - if(startposCMD){ - game->parseFEN((char*)std::string(startPosition).c_str()); - } - - if(trickyposCMD){ - game->parseFEN((char*)std::string(trickyPosition).c_str()); - } - - if(fen){ - game->parseFEN(fen + 4); - } - - if(moves){ - game->executeMoveList(moves + 6); - } - - return 0; -} - -int goCommand(Game* game, char* command){ - // the go command is composed by the following subcommands: - // - depth : sets the depth to the specified value - // - movetime : sets the movetime to the specified value - // - infinite : sets the movetime to infinite - // - wtime : sets the white time to the specified value - // - btime : sets the black time to the specified value - // - winc : sets the white increment to the specified value - // - binc : sets the black increment to the specified value - // - movetime : sets the movetime to the specified value - - // we will search for the first occurrence of a command - char* depth = strstr((char *)command, "depth"); - char* movetime = strstr((char *)command, "movetime"); - char* infinite = strstr((char *)command, "infinite"); - char* wtime = strstr((char *)command, "wtime"); - char* btime = strstr((char *)command, "btime"); - char* winc = strstr((char *)command, "winc"); - char* binc = strstr((char *)command, "binc"); - char* nodes = strstr((char *)command, "nodes"); - - if(depth){ - game->depth = atoi(depth + 6); - game->searchMode = 1; - } - else { - if(movetime){ - game->moveTime = getTime64(); - game->moveTime += atoi(movetime + 9); - game->searchMode = 3; - game->depth = 127; - } - else { - // if no movetime is specified, we set the movetime to infinite - game->moveTime = 0xFFFFFFFFFFFFFFFF; - game->searchMode = 0; - game->depth = 127; - } - - if(infinite){ - game->moveTime = 0xFFFFFFFFFFFFFFFF; - game->searchMode = 0; - game->depth = 127; - } - - if(wtime){ - game->wtime = atoi(wtime + 6); - game->searchMode = 2; // To mark that we are not in infinite mode - } - - if(btime){ - game->btime = atoi(btime + 6); - game->searchMode = 2; // To mark that we are not in infinite mode - } - - if(winc){ - game->winc = atoi(winc + 5); - game->searchMode = 2; // To mark that we are not in infinite mode - } - - if(binc){ - game->binc = atoi(binc + 5); - game->searchMode = 2; // To mark that we are not in infinite mode - } - } - - if(nodes){ - game->hardNodesLimit = atoll(nodes + 6); - } - else { - game->hardNodesLimit = 0xFFFFFFFFFFFFFFFF; - } - - game->startSearch(true); - - return 0; -} - -void execCommand(Game* game, char* command){ - // the exec command is composed by the following subcommands: - // - exec : executes the specified command - - char* exec = strstr((char *)command, "exec"); - - if(exec){ - // We will add more commands as we need them, for now we just have: - // "mayBeZugswang" : returns game->pos.mayBeZugswang() - // "printBB " : calls printBitBoard((BitBoard)bb); - if(strstr((char *)command, "zugswang")){ - std::cout << "game->pos.mayBeZugswang() returned " << game->pos.mayBeZugzwang() << std::endl; - } - else if (strstr((char *)command, "pinned")){ - std::cout << "pinned pieces: \n"; - bool side = game->pos.side; - BitBoard whitePieces = game->pos.occupancies[WHITE]; - BitBoard blackPieces = game->pos.occupancies[BLACK]; - BitBoard pieces = whitePieces | blackPieces; - BitBoard toPrint = 0; - if (side == WHITE){ - BitBoard blackBQ = game->pos.bitboards[8] | game->pos.bitboards[10]; - BitBoard blackRQ = game->pos.bitboards[9] | game->pos.bitboards[10]; - BitBoard ourKing = game->pos.bitboards[5]; - Square ourKingSquare = popLsb(ourKing); - toPrint = getPinnedPieces(pieces, whitePieces, ourKingSquare, blackRQ, blackBQ); - } - else{ - BitBoard whiteBQ = game->pos.bitboards[2] | game->pos.bitboards[4]; - BitBoard whiteRQ = game->pos.bitboards[3] | game->pos.bitboards[4]; - BitBoard ourKing = game->pos.bitboards[11]; - Square ourKingSquare = popLsb(ourKing); - toPrint = getPinnedPieces(pieces, blackPieces, ourKingSquare, whiteRQ, whiteBQ); - } - printBitBoard(toPrint); - } - else if (strstr((char* )command, "btwn")){ - // read the next two squares. Each square is two characters long, so we need to read two characters for each square - char* square1 = command + 10; - std::cout << square1 << "\n"; - char* square2 = square1 + 3; - Square sq1 = squareFromName(square1); - Square sq2 = squareFromName(square2); - BitBoard btwn = squaresBetween[sq1][sq2]; - printBitBoard(btwn); - } - else if(strstr((char *)command, "printBB")){ - char* bb = strstr((char *)command, "printBB"); - // bb is unsigned long long - printBitBoard((BitBoard)std::stoull(bb + 8)); - } - } -} - -#define MAX_INPUT_LENGTH 8192 -void uciLoop(Game* game){ - // The uciLoop is implemented in a way that it can be interrupted by the user, even if the engine is searching - // The user can type "quit" to exit the engine - - std::cin.clear(); - std::cin.sync(); - std::cout.flush(); - - // define user / GUI input buffer - char userInput[MAX_INPUT_LENGTH]; - - std::string input = ""; - - // loop - while(1){ - - // reset the input string - input = ""; - - // read the user input - std::cin.getline(userInput, MAX_INPUT_LENGTH); - - //print received input - //std::cout << "Received input: " << userInput << std::endl; - - // if recived quit during search - if (quit){ - return; - } - - - // make sure the user input is not new line - if (userInput[0] == '\n' || strcmp(userInput, "") == 0){ - continue; - } - - // execute the command - if(executeCommand(game, userInput) == 1 || strcmp(userInput, "quit") == 0){ - break; - } - - // flush the output - std::cout.flush(); - - std::cout << std::flush; - - // clear the input buffer - std::cin.clear(); - - // sync the input buffer - std::cin.sync(); - - // clear the user input buffer - memset(userInput, 0, MAX_INPUT_LENGTH); - } -} - -int inputWaiting(){ -#ifndef WIN32 - fd_set readfds; - struct timeval tv; - FD_ZERO(&readfds); - FD_SET(fileno(stdin), &readfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - select(16, &readfds, 0, 0, &tv); - - return (FD_ISSET(fileno(stdin), &readfds)); -#else - static int init = 0, pipe; - static HANDLE inh; - DWORD dw; - - if (!init) { - init = 1; - inh = GetStdHandle(STD_INPUT_HANDLE); - pipe = !GetConsoleMode(inh, &dw); - if (!pipe) { - SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)); - FlushConsoleInputBuffer(inh); - } - } - - if (pipe) { - if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) return 1; - return dw; - } - - else { - GetNumberOfConsoleInputEvents(inh, &dw); - return dw <= 1 ? 0 : dw; - } -#endif -} - -void readInput(Game *game){ - // bytes to read holder - int bytes; - - // GUI/user input - char input[256] = ""; - char* endc; - - // "listen" to STDIN - if (inputWaiting()) { - // tell engine to stop calculating - game->stopped = 1; - - // loop to read bytes from STDIN - do { - // read bytes from STDIN -#ifndef WIN32 - bytes = read(fileno(stdin), input, 256); -#else - bytes = _read(_fileno(stdin), input, 256); -#endif - } - // until bytes available - while (bytes < 0); - - // searches for the first occurrence of '\n' - endc = strchr(input, '\n'); - - // if found new line set value at pointer to 0 - if (endc) *endc = 0; - - // if input is available - if (strlen(input) > 0) { - // match UCI "quit" command - if (!strcmp(input, "quit")) - { - //std::cout << "morte allo spaghetto volante"< game->moveTime){ - game->stopped = true; - } - readInput(game); -} - -/** - * @brief The getTimeMs function returns the current time in milliseconds. - * @return The current time in milliseconds. - */ -U64 getTime64() { - return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); -} \ No newline at end of file diff --git a/src/uci.h b/src/uci.h deleted file mode 100644 index 38173a0..0000000 --- a/src/uci.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#pragma once -#include "Game.h" -#ifndef _WIN32 -#include -#include // Solves IO problems for some very barebone linux distros -#else -#include -#undef min -#undef max -#include -#endif -#include -#include - -extern bool quit; -extern int movesToGo; // UCI parameter for the moves until the next time control. -extern int moveTime; // UCI parameter for the time per move. -extern int increment; // UCI parameter for the time increment. -extern U64 startTime; // The time when the engine started calculating. -extern U64 stopTime; // The time when the engine must stop calculating. -extern bool timeIsUp; // True if the time is up. -extern bool ponder; // True if the engine is pondering. -extern U8 timeSet; // 0 for infinite, 1 for time per move, 2 for depth, 3 for normal play. -extern std::string hashDumpFile; // Additional opening hash file -extern U32 hashSize; // The size of the hash table in megabytes. -/** - * @brief The getTimeMs function returns the current time in milliseconds. - * @return The current time in milliseconds. - */ -U64 getTime64(); - -/** - * @brief The uciLoop function is the main function of the engine. - * It is called by the main function of the engine. - * It is responsible for interfacing the engine with the GUI. - * @param game The game object. - * @note This function writes to the standard output, which is then redirected to the GUI. - */ -void uciLoop(Game *game); - -/** - * @brief The executeCommand function reads a string and executes the command(s) contained in the string. - * @param game The game object. - * @param command The command string. - * @return The return value is the return value of the command. - */ -int executeCommand(Game *game, char *command); - -/** - * @brief The positionCommand function handles the position command. - * @param game The game object. - * @param command The command string. - * @return The return value is the return value of the command. - */ -int positionCommand(Game *game, char *command); - -/** - * @brief The goCommand function handles the go command. - * @param game The game object. - * @param command The command string. - * @return The return value is the return value of the command. - * @note This function is responsible for the main search loop. - */ -int goCommand(Game *game, char *command); - -/** - * @brief The setOptionCommand function handles the setOption command - * @param command The command string. - * @return The return value is the return value of the command. - */ -int setOptionCommand(char* command); - -/** - * @brief The inputWaiting function waits for input from the GUI. The code is based on the code from Code Monkey King's BBC chess engine which is based on the code from VICE by BlueFeverSoftware. - * @return The return value is the length of the input string (0 means no input). - * @note This function is responsible for async communication with the GUI. - */ -int inputWaiting(); - -/** - * @brief The readInput function reads the input from the GUI. The code is based on the code from Code Monkey King's BBC chess engine which is based on the code from VICE by BlueFeverSoftware. - * It is responsible for async communication with the GUI during the main search loop. It is not responsible for command execution (except for the stop command). - * @param game - */ -void readInput(Game *game); - -/** - * @brief The UCICommunicate function is responsible for mid-search communication with the GUI. - * @param game The game object. - */ -void UCICommunicate(Game *game); - -/** - * @brief The execCommand function directly calls a method. It assumes no context, unless specified, for example, "execCommand game.print()" is equivalent to the print method. - * @param game The game object. - * @param command The command string. - */ -void execCommand(Game *game, char *command); diff --git a/src/visualizer.ipynb b/src/visualizer.ipynb deleted file mode 100644 index 1d17324..0000000 --- a/src/visualizer.ipynb +++ /dev/null @@ -1,918 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "## NEW METHOD\n", - "# curl -L \"https://drive.usercontent.google.com/download?id=1q5Yp_kNA7gClJyFbOMxRkm12p9Qyjc60&confirm=xxx\" -o filename\n", - "# https://drive.google.com/file/d/1q5Yp_kNA7gClJyFbOMxRkm12p9Qyjc60/view?usp=sharing\n", - "## END NEW METHOD " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "\n", - "\n", - "# The following is an implementation of a tuning algorithm for Perseus's HCE. Perseus is a open-source chess engine that is written in C++.\n", - "# We will get an already exported .bin file containing features extracted from the engine HCE. This way, the optimization problem becomes a simple logistic regression problem.\n", - "# The only thing we need to account for is that the linear regression will be done with a slightly modified version of the sigmoid function (with a much larger range),\n", - "# since the engine values are expected to vary between -1000 and 1000.\n", - "# We will use torch to implement the logistic regression and the optimization algorithm.\n", - "# The optimization algorithm will be the AdamW, and we will use weight decay (with a rather small value not to mess the sigmoid scale) to prevent overfitting.\n", - "import torch\n", - "import torch.nn as nn\n", - "import torch.optim as optim\n", - "import numpy as np\n", - "\n", - "# Open the file containing the features. \n", - "ENTRY_BYTE_SIZE = 500\n", - "NUM_FEATURES = ENTRY_BYTE_SIZE - 1 # The last byte is the label.\n", - "NUM_COLORLESS = ENTRY_BYTE_SIZE - 1 - 1 - 20 # 20 is the number of features that are color dependent, 1 is the phase feature, and 1 is the label." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "torch.Size([7082116, 1])\n", - "torch.Size([7082116, 478])\n", - "torch.Size([7082116, 20])\n", - "torch.Size([7082116, 1])\n", - "torch.Size([71537, 1])\n", - "torch.Size([71537, 478])\n", - "torch.Size([71537, 20])\n", - "torch.Size([71537, 1])\n" - ] - } - ], - "source": [ - "with open('out.bin', 'rb') as f:\n", - " features = f.read()\n", - " features = np.frombuffer(features, dtype=np.int8)\n", - "# Reshape the features to have the correct shape. Do it not as a view, but as a copy.\n", - "features = features.reshape(-1, ENTRY_BYTE_SIZE).copy()\n", - "\n", - "# Shuffle the features.\n", - "np.random.seed(47) # 47 my beloved.\n", - "np.random.shuffle(features)\n", - "\n", - "torch.manual_seed(47) # 47 my sweethearth.\n", - "\n", - "# Split the features. The first byte is the phase, then 478 colorless weights, followed by 20 color dependent features, and the last byte is the label.\n", - "phases = features[:, 0]\n", - "colorless = features[:, 1:NUM_COLORLESS + 1]\n", - "color_dependent = features[:, NUM_COLORLESS + 1:NUM_COLORLESS + 1 + 20]\n", - "labels = features[:, -1]\n", - "\n", - "\n", - "# Divide the features into training and testing sets.\n", - "train_size = int(0.99 * len(features))\n", - "phases_train = phases[:train_size]\n", - "colorless_train = colorless[:train_size]\n", - "color_dependent_train = color_dependent[:train_size]\n", - "labels_train = labels[:train_size]\n", - "\n", - "phases_test = phases[train_size:]\n", - "colorless_test = colorless[train_size:]\n", - "color_dependent_test = color_dependent[train_size:]\n", - "labels_test = labels[train_size:]\n", - "\n", - "# Convert the numpy arrays to torch tensors.\n", - "phases_train = torch.tensor(phases_train, dtype=torch.float32).unsqueeze(1)\n", - "colorless_train = torch.tensor(colorless_train, dtype=torch.float32)\n", - "color_dependent_train = torch.tensor(color_dependent_train, dtype=torch.float32)\n", - "labels_train = torch.tensor(labels_train, dtype=torch.float32).unsqueeze(1)\n", - "\n", - "phases_test = torch.tensor(phases_test, dtype=torch.float32).unsqueeze(1)\n", - "colorless_test = torch.tensor(colorless_test, dtype=torch.float32)\n", - "color_dependent_test = torch.tensor(color_dependent_test, dtype=torch.float32)\n", - "labels_test = torch.tensor(labels_test, dtype=torch.float32).unsqueeze(1)\n", - "\n", - "print(phases_train.shape)\n", - "print(colorless_train.shape)\n", - "print(color_dependent_train.shape)\n", - "print(labels_train.shape)\n", - "\n", - "print(phases_test.shape)\n", - "print(colorless_test.shape)\n", - "print(color_dependent_test.shape)\n", - "print(labels_test.shape)\n", - "\n", - "# Delete the numpy array to free up memory.\n", - "del features\n", - "del phases\n", - "del colorless\n", - "del color_dependent\n", - "del labels" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a dataset class\n", - "import torch.utils.data as data\n", - "from torch.utils.data import DataLoader\n", - "\n", - "class ChessDataset(data.Dataset):\n", - " def __init__(self, phases, colorless, color_dependent, labels):\n", - " self.phases = phases\n", - " self.colorless = colorless\n", - " self.color_dependent = color_dependent\n", - " self.labels = labels\n", - " \n", - " def __len__(self):\n", - " return len(self.labels)\n", - "\n", - " def __getitem__(self, idx):\n", - " return self.phases[idx], self.colorless[idx], self.color_dependent[idx], self.labels[idx]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "defaultcolorless = [\n", - " 130, 432, 447, 623, 1369,\n", - "\n", - " -1, 6, 6, 3, 3, 0, 3, 7 ,\n", - " 36, 37, 22, 35, 23, 39, 15, -3 ,\n", - " 3, 1, 7, 11, 24, 12, 3, -5 ,\n", - " -1, -3, 0, 4, 6, 1, -4, -1 ,\n", - " -9, -11, -6, 2, 3, 0, -7, -1 ,\n", - " -9, -7, -9, -11, -9, -16, 8, 3 ,\n", - " -43, -43, -28, -33, -27, -17, 9, -11 ,\n", - " -4, 2, 1, 1, -1, -1, -8, 3 ,\n", - "\n", - " -158, -92, -59, -10, 23, -45, -53, -85 ,\n", - " 14, 43, 72, 102, 70, 167, 38, 59 ,\n", - " 5, 51, 66, 94, 164, 151, 97, 58 ,\n", - " 15, 21, 50, 91, 58, 94, 46, 84 ,\n", - " -6, 5, 18, 28, 47, 39, 58, 30 ,\n", - " -43, -19, -6, 1, 17, 7, 27, 9 ,\n", - " -79, -62, -42, -28, -12, -25, -6, -4 ,\n", - " -77, -35, -42, -10, -3, 0, -30, -40 ,\n", - "\n", - " -17, -40, -47, -83, -63, -60, -13, -35 ,\n", - " 18, 50, 28, 29, 60, 57, 34, 1 ,\n", - " 1, 30, 36, 66, 63, 112, 70, 56 ,\n", - " -5, 11, 36, 70, 61, 52, 22, 12 ,\n", - " -4, -4, 7, 44, 45, 6, 10, 39 ,\n", - " 4, 35, 14, 12, 7, 19, 52, 35 ,\n", - " -9, -20, 22, -31, -5, 3, 39, 46 ,\n", - " 8, 47, 9, -4, 0, 4, 22, 24 ,\n", - "\n", - " 20, 8, 4, 5, 24, 46, 51, 71 ,\n", - " 49, 45, 54, 87, 67, 110, 83, 115 ,\n", - " 0, 35, 30, 37, 97, 102, 133, 112 ,\n", - " -3, 11, 8, 14, 17, 28, 49, 60 ,\n", - " -25, -26, -22, -17, -17, -30, 26, 24 ,\n", - " -30, -23, -28, -32, -23, -16, 58, 27 ,\n", - " -65, -58, -31, -39, -23, -23, 26, -13 ,\n", - " -12, -8, -8, 0, 12, 12, 16, -5 ,\n", - "\n", - " -20, -17, 14, 44, 48, 68, 73, 35 ,\n", - " 42, 2, 11, 27, 38, 82, 52, 115 ,\n", - " 17, 14, 6, 30, 51, 133, 118, 130 ,\n", - " 4, -2, 6, 3, 5, 37, 46, 56 ,\n", - " 0, -9, -9, -3, 4, 2, 24, 48 ,\n", - " 9, 14, 0, -13, -15, 8, 45, 49 ,\n", - " -18, -23, 2, -5, -1, -2, 28, 54 ,\n", - " 2, 19, 21, 23, 17, -3, 17, 12 ,\n", - "\n", - " 17, 43, 41, 5, 17, 45, 81, 46 ,\n", - " 56, 108, 63, 97, 83, 105, 137, 100 ,\n", - " 23, 107, 53, 38, 71, 130, 125, 89 ,\n", - " 31, 41, 12, -33, -26, 19, 43, 3 ,\n", - " 19, 20, -24, -68, -61, -20, -19, -50 ,\n", - " 49, 77, -1, -25, -24, -20, 44, 24 ,\n", - " 130, 67, 68, 16, 21, 33, 128, 145 ,\n", - " 152, 204, 171, 31, 121, 74, 186, 175 ,\n", - "\n", - " -45, -10, 12, 26, 40, 50, 62, 75, 84,\n", - " -61, -14, 7, 19, 39, 50, 59, 64, 67, 72, 84, 92, 96, 81,\n", - " -10, -8, -3, 0, 6, 6, 8, 14, 20, 35, 37, 41, 46, 57, 47,\n", - " -20, -109, -46, -16, 2, 7, 14, 20, 27, 34, 41, 48, 52, 59, 62, 69, 71, 72, 78, 96, 101, 125, 136, 140, 151, 141, 89, 73, \n", - "\n", - " 20, 21, 14, 13, 9, 4, 2, 1, \n", - " 0, 2, -20, -20, 20, 62, 79,\n", - " -4, 30, 25, 13, 45, 30, 21, 35,\n", - "\n", - " # EG\n", - " 153, 437, 452, 773, 1379,\n", - "\n", - " -1, -8, -4, -4, -2, -1, -3, -6 ,\n", - " 53, 50, 46, 40, 43, 39, 44, 54 ,\n", - " 30, 29, 25, 17, 16, 19, 23, 25 ,\n", - " 16, 14, 3, -4, -6, 0, 6, 6 ,\n", - " 6, 6, -6, -11, -9, -7, -1, -4 ,\n", - " -21, -24, -26, -22, -18, -16, -24, -28 ,\n", - " -41, -44, -39, -33, -35, -37, -48, -56 ,\n", - " -1, -7, -4, -5, -1, -2, 2, -5 ,\n", - "\n", - " -61, -19, 5, -10, -6, -36, -27, -84 ,\n", - " 52, 61, 43, 37, 22, 9, 43, 19 ,\n", - " 33, 33, 61, 50, 23, 14, 7, 6 ,\n", - " 23, 28, 51, 49, 49, 42, 26, 4 ,\n", - " 20, 14, 43, 44, 50, 32, 10, 12 ,\n", - " -27, -21, -12, 18, 14, -11, -23, -19 ,\n", - " -50, -43, -38, -28, -36, -37, -50, -40 ,\n", - " -14, -10, -1, 10, 10, -7, -4, 6 ,\n", - "\n", - " 19, 26, 21, 26, 20, 7, 11, 2 ,\n", - " 57, 62, 60, 49, 35, 44, 55, 49 ,\n", - " 56, 47, 48, 25, 24, 32, 33, 40 ,\n", - " 28, 32, 26, 41, 27, 29, 21, 22 ,\n", - " 8, 21, 33, 31, 28, 24, 15, -10 ,\n", - " -15, -4, 2, 13, 24, 8, -16, -19 ,\n", - " -33, -47, -51, -15, -23, -30, -33, -57 ,\n", - " 3, 15, 16, 14, 16, 28, 2, -23 ,\n", - "\n", - " 59, 61, 71, 61, 51, 54, 50, 43 ,\n", - " 109, 124, 117, 93, 95, 86, 93, 82 ,\n", - " 88, 85, 86, 71, 53, 48, 50, 41 ,\n", - " 69, 61, 70, 59, 42, 43, 41, 33 ,\n", - " 49, 48, 46, 41, 42, 44, 25, 20 ,\n", - " 17, 12, 8, 15, 7, 3, -30, -20 ,\n", - " -16, -14, -13, -9, -23, -26, -43, -41 ,\n", - " 35, 25, 33, 20, 11, 22, 12, 18 ,\n", - "\n", - " 54, 64, 84, 77, 85, 73, 38, 54 ,\n", - " 106, 148, 161, 166, 182, 144, 133, 130 ,\n", - " 89, 96, 143, 144, 151, 131, 96, 102 ,\n", - " 73, 91, 101, 130, 149, 132, 131, 115 ,\n", - " 51, 80, 83, 115, 112, 110, 94, 88 ,\n", - " 4, 31, 47, 62, 75, 69, 41, 25 ,\n", - " -28, -25, -18, 0, 1, -21, -48, -63 ,\n", - " 7, 5, 8, 27, 18, 15, 1, -1 ,\n", - "\n", - " -41, 15, 27, 56, 48, 61, 57, -38 ,\n", - " 96, 143, 140, 128, 146, 160, 155, 119 ,\n", - " 88, 129, 145, 148, 156, 151, 148, 100 ,\n", - " 56, 102, 130, 140, 141, 138, 117, 78 ,\n", - " 31, 76, 109, 130, 131, 112, 92, 65 ,\n", - " 1, 34, 63, 86, 87, 77, 47, 26 ,\n", - " -43, -5, 12, 34, 38, 27, -5, -47 ,\n", - " -43, -24, 3, 34, 10, 28, -15, -63 ,\n", - "\n", - " -76, -5, 31, 45, 57, 73, 71, 68, 52,\n", - " -48, -32, -1, 25, 40, 56, 66, 70, 76, 76, 69, 67, 63, 56,\n", - " -90, 19, 41, 61, 70, 83, 91, 92, 98, 103, 108, 112, 117, 110, 114,\n", - " -12, -78, -69, -51, -19, 9, 48, 78, 98, 107, 118, 128, 140, 149, 158, 159, 175, 181, 184, 179, 184, 170, 165, 158, 156, 145, 116, 105,\n", - "\n", - " 48, 17, 7, 29, 7, 21, 2, 1,\n", - " 0, -34, -21, 18, 66, 171, 263,\n", - " 8, -2, 9, 4, 97, -8, 20, 30\n", - "\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "torch.Size([1, 956])\n" - ] - } - ], - "source": [ - "default = torch.tensor(default, dtype=torch.float32).view(1, -1)\n", - "print(default.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "torch.Size([1, 956])\n", - "torch.Size([1, 478])\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_884116/1937539170.py:14: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", - " model.load_state_dict(torch.load(ptfile))\n" - ] - } - ], - "source": [ - "###### Now we will read the default values for the features. These values are the ones that the engine uses when no tuning is applied.\n", - "# with open('default.bin', 'rb') as f:\n", - "# default = f.read()\n", - "# default = np.frombuffer(default, dtype=np.int8)\n", - "# default = default.reshape(-1, NUM_FEATURES)\n", - "\n", - "\n", - "\n", - "# Convert to torch tensor.\n", - "# default = torch.zeros((NUM_FEATURES-1) * 2) #torch.tensor(default, dtype=torch.float32)\n", - "\n", - "def load_model(ptfile):\n", - " model = HCE()\n", - " model.load_state_dict(torch.load(ptfile))\n", - " return model\n", - "\n", - "class BoundedPolynomial(nn.Module):\n", - " # A simple polynomial layer that clamps the output between low and high.\n", - " def __init__(self, degree, low = -500, high = 500):\n", - " super(BoundedPolynomial, self).__init__()\n", - " self.degree = degree\n", - " self.low = low\n", - " self.high = high\n", - " self.poly = nn.Linear(degree, 1)\n", - " \n", - " def forward(self, x):\n", - " x = x.unsqueeze(1)\n", - " x = torch.cat([x ** i for i in range(1, self.degree + 1)], dim=1)\n", - " return torch.clamp(self.poly(x), self.low, self.high)\n", - "\n", - "# Create the model.\n", - "class HCE(nn.Module):\n", - " def __init__(self):\n", - " super(HCE, self).__init__()\n", - " self.mgfc = nn.Linear(NUM_COLORLESS, 1, bias=False)\n", - " self.egfc = nn.Linear(NUM_COLORLESS, 1, bias=False)\n", - " self.mgcolored = nn.Linear(10, 1, bias = False)\n", - " self.egcolored = nn.Linear(10, 1, bias = False)\n", - " self.mgpolynomial = BoundedPolynomial(2)\n", - " self.egpolynomial = BoundedPolynomial(2)\n", - " self.K = 2.0 / 400 # May need tuning, refer to Andrew Grant's Ethereal tuning guide.\n", - " self.default = default\n", - " \n", - " def load_default(self):\n", - " # Default is exactly NUM_FEATURES * 2 long, since it contains both the mg and eg values.\n", - " self.mgfc.weight.data = self.default[:, :NUM_FEATURES-1].reshape(1, -1)\n", - " self.egfc.weight.data = self.default[:, NUM_FEATURES-1:].reshape(1, -1)\n", - "\n", - " def forward(self, phase, colorless, colored):\n", - " # Calculate the mg and eg values.\n", - " mg = self.mgfc(colorless) * phase\n", - " eg = self.egfc(colorless) * (1 - phase)\n", - " # Calculate the colored features. First, split the features\n", - " wking = colored[:, :10]\n", - " bking = colored[:, 10:]\n", - " # Get mg and eg term for both colors\n", - " wmgk = self.mgcolored(wking) * phase\n", - " bmgk = self.mgcolored(bking) * phase\n", - " wegk = self.egcolored(wking) * (1 - phase)\n", - " begk = self.egcolored(bking) * (1 - phase)\n", - " # Pass through the polynomial layer.\n", - " wmgk = self.mgpolynomial(wmgk) \n", - " bmgk = self.mgpolynomial(bmgk)\n", - " wegk = self.egpolynomial(wegk)\n", - " begk = self.egpolynomial(begk)\n", - " # Sum the terms.\n", - " mg += wmgk - bmgk\n", - " eg += wegk - begk\n", - " # Calculate the sigmoid.\n", - " return 1 / (1 + torch.exp(-self.K * (mg + eg)))\n", - "\n", - "# Create the model and load the default values.\n", - "# model = load_model(\"runs/modelpawnshelter_2047.pt\")\n", - "model = HCE()\n", - "# model.load_default()\n", - "# print(model.default.shape)\n", - "# print(model.mgfc.weight.data.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "MSELoss()" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "torch.set_float32_matmul_precision('high')\n", - "# Only this extra line of code is required to use oneDNN Graph\n", - "# torch.jit.enable_onednn_fusion(True)\n", - "\n", - "\n", - "# Create the dataset and the dataloader. Use large batch size to speed up training and avoid overfitting (this is a very simple problem).\n", - "train_dataset = ChessDataset(phases_train, colorless_train, color_dependent_train, labels_train)\n", - "test_dataset = ChessDataset(phases_test, colorless_test, color_dependent_test, labels_test)\n", - "\n", - "BATCH_SIZE = 16384 * 16\n", - "train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=30, pin_memory=True)\n", - "test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=30, pin_memory=True)\n", - "\n", - "# model = load_model(\"runs/modelpawnshelter_13.pt\")\n", - "# Compile the model.\n", - "# model = torch.compile(m)\n", - "# model = HCE()\n", - "# Find the optimal K value.\n", - "# K = model.find_optimal_k(train_loader)\n", - "# print(\"Optimal K value:\", K)\n", - "\n", - "# Create the optimizer.\n", - "optimizer = optim.AdamW(model.parameters(), lr=.001, weight_decay=0.001) # We use a bigger than usual learning rate, since the scale of the weights is much larger.\n", - "\n", - "# Create the loss function. The original paper uses MSE.\n", - "criterion = nn.MSELoss()\n", - "\n", - "# Create the scheduler.\n", - "scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=8, gamma=0.95)\n", - "\n", - "# Train the model.\n", - "EPOCHS = 1024\n", - "\n", - "\n", - "\n", - "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", - "model.to(device)\n", - "criterion.to(device)\n", - "\n", - "# Create the tensorboard writer.\n", - "# from torch.utils.tensorboard import SummaryWriter\n", - "# writer = SummaryWriter(log_dir=\"logs\", flush_secs=10)\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(Test) Epoch 2048, Loss: 0.19046588242053986 Time: 18.366507053375244 s\n", - "(Test) Epoch 2049, Loss: 0.19045430421829224 Time: 17.694855451583862 s\n", - "(Test) Epoch 2050, Loss: 0.1904429793357849 Time: 17.717244386672974 s\n", - "(Test) Epoch 2051, Loss: 0.19043231010437012 Time: 17.671803951263428 s\n", - "(Test) Epoch 2052, Loss: 0.1904216706752777 Time: 17.57187056541443 s\n", - "(Test) Epoch 2053, Loss: 0.19041132926940918 Time: 18.18381428718567 s\n", - "(Test) Epoch 2054, Loss: 0.1904008388519287 Time: 18.131683826446533 s\n", - "(Test) Epoch 2055, Loss: 0.19039058685302734 Time: 17.89490056037903 s\n", - "(Test) Epoch 2056, Loss: 0.19038096070289612 Time: 18.025938272476196 s\n", - "(Test) Epoch 2057, Loss: 0.1903712898492813 Time: 18.177820920944214 s\n", - "(Test) Epoch 2058, Loss: 0.19036176800727844 Time: 17.945281505584717 s\n", - "(Test) Epoch 2059, Loss: 0.19035232067108154 Time: 18.11404299736023 s\n", - "(Test) Epoch 2060, Loss: 0.19034293293952942 Time: 18.00236177444458 s\n", - "(Test) Epoch 2061, Loss: 0.19033369421958923 Time: 18.059348821640015 s\n", - "(Test) Epoch 2062, Loss: 0.19032439589500427 Time: 18.136505603790283 s\n", - "(Test) Epoch 2063, Loss: 0.1903150975704193 Time: 17.961714029312134 s\n", - "(Test) Epoch 2064, Loss: 0.19030635058879852 Time: 17.98085594177246 s\n", - "(Test) Epoch 2065, Loss: 0.1902976930141449 Time: 18.27790331840515 s\n", - "(Test) Epoch 2066, Loss: 0.1902892142534256 Time: 17.945488929748535 s\n", - "(Test) Epoch 2067, Loss: 0.19028082489967346 Time: 18.076006650924683 s\n", - "(Test) Epoch 2068, Loss: 0.1902725100517273 Time: 18.179412603378296 s\n", - "(Test) Epoch 2069, Loss: 0.19026421010494232 Time: 17.869565963745117 s\n", - "(Test) Epoch 2070, Loss: 0.19025593996047974 Time: 17.935252904891968 s\n", - "(Test) Epoch 2071, Loss: 0.19024768471717834 Time: 17.98635983467102 s\n", - "(Test) Epoch 2072, Loss: 0.1902398318052292 Time: 17.903342723846436 s\n", - "(Test) Epoch 2073, Loss: 0.19023214280605316 Time: 17.86142373085022 s\n", - "(Test) Epoch 2074, Loss: 0.19022437930107117 Time: 17.94640278816223 s\n", - "(Test) Epoch 2075, Loss: 0.1902167648077011 Time: 18.126947164535522 s\n", - "(Test) Epoch 2076, Loss: 0.19020909070968628 Time: 18.03683829307556 s\n", - "(Test) Epoch 2077, Loss: 0.190201535820961 Time: 18.159971475601196 s\n", - "(Test) Epoch 2078, Loss: 0.19019421935081482 Time: 17.855421543121338 s\n", - "(Test) Epoch 2079, Loss: 0.19018688797950745 Time: 17.795875549316406 s\n", - "(Test) Epoch 2080, Loss: 0.19017992913722992 Time: 17.91045045852661 s\n", - "(Test) Epoch 2081, Loss: 0.19017310440540314 Time: 17.93821096420288 s\n", - "(Test) Epoch 2082, Loss: 0.19016623497009277 Time: 17.88122582435608 s\n", - "(Test) Epoch 2083, Loss: 0.19015948474407196 Time: 17.99340319633484 s\n", - "(Test) Epoch 2084, Loss: 0.19015279412269592 Time: 17.844560861587524 s\n", - "(Test) Epoch 2085, Loss: 0.1901460587978363 Time: 17.790934562683105 s\n", - "(Test) Epoch 2086, Loss: 0.19013936817646027 Time: 17.95338726043701 s\n", - "(Test) Epoch 2087, Loss: 0.19013270735740662 Time: 17.957857847213745 s\n", - "(Test) Epoch 2088, Loss: 0.1901264637708664 Time: 17.864428520202637 s\n", - "(Test) Epoch 2089, Loss: 0.19012019038200378 Time: 17.844690561294556 s\n", - "(Test) Epoch 2090, Loss: 0.19011417031288147 Time: 17.855050563812256 s\n", - "(Test) Epoch 2091, Loss: 0.19010798633098602 Time: 17.94197964668274 s\n", - "(Test) Epoch 2092, Loss: 0.19010193645954132 Time: 17.68209671974182 s\n", - "(Test) Epoch 2093, Loss: 0.1900959461927414 Time: 17.797520399093628 s\n", - "(Test) Epoch 2094, Loss: 0.19008994102478027 Time: 17.887896060943604 s\n", - "(Test) Epoch 2095, Loss: 0.19008399546146393 Time: 17.84813666343689 s\n", - "(Test) Epoch 2096, Loss: 0.19007834792137146 Time: 17.86475706100464 s\n", - "(Test) Epoch 2097, Loss: 0.19007283449172974 Time: 17.850351333618164 s\n", - "(Test) Epoch 2098, Loss: 0.19006730616092682 Time: 17.892409801483154 s\n", - "(Test) Epoch 2099, Loss: 0.1900617778301239 Time: 17.967394828796387 s\n", - "(Test) Epoch 2100, Loss: 0.19005627930164337 Time: 17.948779821395874 s\n", - "(Test) Epoch 2101, Loss: 0.19005076587200165 Time: 18.03679895401001 s\n", - "(Test) Epoch 2102, Loss: 0.19004538655281067 Time: 17.761699199676514 s\n", - "(Test) Epoch 2103, Loss: 0.1900400072336197 Time: 17.91832423210144 s\n", - "(Test) Epoch 2104, Loss: 0.19003494083881378 Time: 18.043102741241455 s\n", - "(Test) Epoch 2105, Loss: 0.19002991914749146 Time: 17.80357789993286 s\n", - "(Test) Epoch 2106, Loss: 0.1900249719619751 Time: 18.042280197143555 s\n", - "(Test) Epoch 2107, Loss: 0.19001998007297516 Time: 18.051717281341553 s\n", - "(Test) Epoch 2108, Loss: 0.19001491367816925 Time: 17.9284770488739 s\n", - "(Test) Epoch 2109, Loss: 0.1900099217891693 Time: 18.04370427131653 s\n", - "(Test) Epoch 2110, Loss: 0.1900051385164261 Time: 17.83632493019104 s\n", - "(Test) Epoch 2111, Loss: 0.19000020623207092 Time: 17.969871997833252 s\n", - "(Test) Epoch 2112, Loss: 0.18999554216861725 Time: 17.97277522087097 s\n", - "(Test) Epoch 2113, Loss: 0.18999092280864716 Time: 17.792067289352417 s\n", - "(Test) Epoch 2114, Loss: 0.18998631834983826 Time: 17.88109278678894 s\n", - "(Test) Epoch 2115, Loss: 0.18998166918754578 Time: 17.96690058708191 s\n", - "(Test) Epoch 2116, Loss: 0.1899769902229309 Time: 18.017014026641846 s\n", - "(Test) Epoch 2117, Loss: 0.1899724155664444 Time: 17.73807978630066 s\n", - "(Test) Epoch 2118, Loss: 0.18996794521808624 Time: 17.871896743774414 s\n", - "(Test) Epoch 2119, Loss: 0.1899634152650833 Time: 17.861659288406372 s\n", - "(Test) Epoch 2120, Loss: 0.18995925784111023 Time: 18.02745032310486 s\n", - "(Test) Epoch 2121, Loss: 0.18995510041713715 Time: 17.94326138496399 s\n", - "(Test) Epoch 2122, Loss: 0.18995092809200287 Time: 17.99027991294861 s\n", - "(Test) Epoch 2123, Loss: 0.1899467557668686 Time: 18.12178611755371 s\n", - "(Test) Epoch 2124, Loss: 0.18994258344173431 Time: 17.859638452529907 s\n", - "(Test) Epoch 2125, Loss: 0.18993844091892242 Time: 17.686264514923096 s\n", - "(Test) Epoch 2126, Loss: 0.18993434309959412 Time: 17.740259647369385 s\n", - "(Test) Epoch 2127, Loss: 0.1899302750825882 Time: 17.946974754333496 s\n", - "(Test) Epoch 2128, Loss: 0.1899263709783554 Time: 17.79047417640686 s\n", - "(Test) Epoch 2129, Loss: 0.18992245197296143 Time: 17.88247776031494 s\n", - "(Test) Epoch 2130, Loss: 0.18991854786872864 Time: 17.932412147521973 s\n", - "(Test) Epoch 2131, Loss: 0.18991465866565704 Time: 17.764833211898804 s\n", - "(Test) Epoch 2132, Loss: 0.18991081416606903 Time: 17.879523992538452 s\n", - "(Test) Epoch 2133, Loss: 0.1899069845676422 Time: 17.816821575164795 s\n", - "(Test) Epoch 2134, Loss: 0.1899031698703766 Time: 17.73190951347351 s\n", - "(Test) Epoch 2135, Loss: 0.18989938497543335 Time: 17.883602142333984 s\n", - "(Test) Epoch 2136, Loss: 0.1898958832025528 Time: 17.882017135620117 s\n", - "(Test) Epoch 2137, Loss: 0.18989241123199463 Time: 17.863783836364746 s\n", - "(Test) Epoch 2138, Loss: 0.18988879024982452 Time: 17.95275616645813 s\n", - "(Test) Epoch 2139, Loss: 0.18988525867462158 Time: 17.89158344268799 s\n", - "(Test) Epoch 2140, Loss: 0.18988174200057983 Time: 17.818190097808838 s\n", - "(Test) Epoch 2141, Loss: 0.18987824022769928 Time: 17.857386589050293 s\n", - "(Test) Epoch 2142, Loss: 0.18987484276294708 Time: 18.00757098197937 s\n", - "(Test) Epoch 2143, Loss: 0.1898714154958725 Time: 18.040676593780518 s\n", - "(Test) Epoch 2144, Loss: 0.18986806273460388 Time: 17.81414270401001 s\n", - "(Test) Epoch 2145, Loss: 0.18986468017101288 Time: 17.94846749305725 s\n", - "(Test) Epoch 2146, Loss: 0.18986137211322784 Time: 17.7609121799469 s\n", - "(Test) Epoch 2147, Loss: 0.1898580938577652 Time: 17.982274532318115 s\n", - "(Test) Epoch 2148, Loss: 0.18985478579998016 Time: 17.819497108459473 s\n", - "(Test) Epoch 2149, Loss: 0.1898515373468399 Time: 17.842528104782104 s\n", - "(Test) Epoch 2150, Loss: 0.18984831869602203 Time: 17.795081615447998 s\n", - "(Test) Epoch 2151, Loss: 0.18984514474868774 Time: 17.651391983032227 s\n", - "(Test) Epoch 2152, Loss: 0.18984214961528778 Time: 17.841092824935913 s\n", - "(Test) Epoch 2153, Loss: 0.18983907997608185 Time: 17.76475715637207 s\n", - "(Test) Epoch 2154, Loss: 0.18983601033687592 Time: 18.042734146118164 s\n", - "(Test) Epoch 2155, Loss: 0.18983295559883118 Time: 18.038702487945557 s\n", - "(Test) Epoch 2156, Loss: 0.18982991576194763 Time: 17.66823101043701 s\n", - "(Test) Epoch 2157, Loss: 0.18982690572738647 Time: 17.965335845947266 s\n", - "(Test) Epoch 2158, Loss: 0.18982388079166412 Time: 17.82914662361145 s\n", - "(Test) Epoch 2159, Loss: 0.18982093036174774 Time: 17.74437117576599 s\n", - "(Test) Epoch 2160, Loss: 0.18981803953647614 Time: 17.981677532196045 s\n", - "(Test) Epoch 2161, Loss: 0.18981517851352692 Time: 17.68855309486389 s\n", - "(Test) Epoch 2162, Loss: 0.1898123174905777 Time: 17.51658797264099 s\n", - "(Test) Epoch 2163, Loss: 0.18980944156646729 Time: 17.701830625534058 s\n", - "(Test) Epoch 2164, Loss: 0.1898064911365509 Time: 17.74875569343567 s\n", - "(Test) Epoch 2165, Loss: 0.1898035705089569 Time: 17.673258066177368 s\n", - "(Test) Epoch 2166, Loss: 0.1898006796836853 Time: 17.478657245635986 s\n", - "(Test) Epoch 2167, Loss: 0.18979789316654205 Time: 17.520290851593018 s\n" - ] - } - ], - "source": [ - "import time\n", - "\n", - "criterion = nn.L1Loss()\n", - "for epoch in range(2048, 1024+2048):\n", - " model.train()\n", - " running_loss = 0.0\n", - " epoch_start = time.time()\n", - " for i, (phase, colorless, color_dependent, labels) in enumerate(train_loader):\n", - " phase, colorless, color_dependent, labels = phase.to(device, non_blocking = True), colorless.to(device, non_blocking = True), color_dependent.to(device, non_blocking = True), labels.to(device, non_blocking = True)\n", - " for param in model.parameters():\n", - " param.grad = None\n", - " y_pred = model(phase, colorless, color_dependent)\n", - " loss = criterion(y_pred, labels)\n", - " # print(f\"Epoch {epoch}, Batch {i} calculate \", end=\"\\r\")\n", - " loss.backward()\n", - " # print(f\"Epoch {epoch}, Batch {i} backward \", end=\"\\r\")\n", - " optimizer.step()\n", - " # print(f\"Epoch {epoch}, Batch {i} step \", end=\"\\r\")\n", - " \n", - " #if i % 27 == 26:\n", - " # writer.add_scalar('Loss/train', running_loss / 8, epoch * len(train_loader) + i)\n", - " #print(f\"(Train) Epoch {epoch}, Batch {i}, Loss: {running_loss / 27} \", e\n", - " scheduler.step()\n", - " model.eval()\n", - " running_loss = 0.0\n", - " for i, (phase, colorless, color_dependent, labels) in enumerate(test_loader):\n", - " phase, colorless, color_dependent, labels = phase.to(device, non_blocking = True), colorless.to(device, non_blocking = True), color_dependent.to(device, non_blocking = True), labels.to(device, non_blocking = True)\n", - " y_pred = model(phase, colorless, color_dependent)\n", - " loss = criterion(y_pred, labels)\n", - " running_loss += loss.item()\n", - "\n", - " # Save the model.\n", - " torch.save(model.state_dict(), f\"runs/modelpawnshelter_{epoch}.pt\")\n", - "\n", - " epoch_end = time.time()\n", - " print(f\"(Test) Epoch {epoch}, Loss: {running_loss / len(test_loader)} Time: {epoch_end - epoch_start} s\")\n", - "\n", - " # Save the optimizer.\n", - " # torch.save(optimizer.state_dict(), f\"optimizer_{epoch}.pt\")\n", - "\n", - "# Save final model.\n", - "torch.save(model.state_dict(), \"modelSGD.pt\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "def visualize(model):\n", - " # Visualize the model. The weights are divided in mg and eg.\n", - " # The first 5 weights are the material values.\n", - " # Then, 64 * 6 weights are the piece square tables.\n", - " # Then 9, 14, 15 and 28 piece mobility features.\n", - " # Visualize these weights using matplotlib and heatmaps.\n", - " weights = model.mgfc.weight.data[0]\n", - " # Material values.\n", - " material = weights[:5]\n", - " # Piece square tables.\n", - " pst = weights[5:5+64*6].reshape(6, 64)\n", - " # Piece mobility features.\n", - " knight_mobility = weights[5+64*6:5+64*6+9]\n", - " bishop_mobility = weights[5+64*6+9:5+64*6+9+14]\n", - " rook_mobility = weights[5+64*6+9+14:5+64*6+9+14+15]\n", - " queen_mobility = weights[5+64*6+9+14+15:5+64*6+9+14+15+28]\n", - " # Create the plots. First, plot the psqt. To do this, we need to:\n", - " # Add the material values to the pst (excluding the king).\n", - " pst[0, :] += material[0]\n", - " pst[1, :] += material[1]\n", - " pst[2, :] += material[2]\n", - " pst[3, :] += material[3]\n", - " pst[4, :] += material[4]\n", - " # Now plot the pst.\n", - " fig, axs = plt.subplots(2, 3)\n", - " # Make the figure bigger using figure() method.\n", - " fig.set_size_inches(18.5, 10.5)\n", - " fig.suptitle(\"Piece Square Tables\")\n", - " for i in range(6):\n", - " axs[i//3, i%3].imshow(pst[i].reshape(8, 8), cmap='hot', interpolation='nearest')\n", - " axs[i//3, i%3].set_title(\"Piece: \" + str(i))\n", - " # Add the value text to the plot.\n", - " for y in range(8):\n", - " for x in range(8):\n", - " axs[i//3, i%3].text(x, y, str(round(pst[i, y*8 + x].item())), color='black', ha='center', va='center')\n", - " plt.show()\n", - " # Now show the mobility features. For each piece, plot the mobility features using a bar plot.\n", - " fig, axs = plt.subplots(2, 2)\n", - " fig.set_size_inches(12.5, 6.5)\n", - " fig.suptitle(\"Piece Mobility Features\")\n", - " axs[0, 0].bar(range(9), knight_mobility)\n", - " axs[0, 0].set_title(\"Knight Mobility\")\n", - " axs[0, 1].bar(range(14), bishop_mobility)\n", - " axs[0, 1].set_title(\"Bishop Mobility\")\n", - " axs[1, 0].bar(range(15), rook_mobility)\n", - " axs[1, 0].set_title(\"Rook Mobility\")\n", - " axs[1, 1].bar(range(28), queen_mobility)\n", - " axs[1, 1].set_title(\"Queen Mobility\") \n", - " # Add the value text to the plot.\n", - " for i in range(9):\n", - " axs[0, 0].text(i, knight_mobility[i], str(round(knight_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " for i in range(14):\n", - " axs[0, 1].text(i, bishop_mobility[i], str(round(bishop_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " for i in range(15):\n", - " axs[1, 0].text(i, rook_mobility[i], str(round(rook_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " for i in range(28):\n", - " axs[1, 1].text(i, queen_mobility[i], str(round(queen_mobility[i].item())), color='black', ha='center', va='bottom')\n", - "\n", - " # Now for eg.\n", - " weights = model.egfc.weight.data[0]\n", - " # Material values.\n", - " material = weights[:5]\n", - " # Piece square tables.\n", - " pst = weights[5:5+64*6].reshape(6, 64)\n", - " # Piece mobility features.\n", - " knight_mobility = weights[5+64*6:5+64*6+9]\n", - " bishop_mobility = weights[5+64*6+9:5+64*6+9+14]\n", - " rook_mobility = weights[5+64*6+9+14:5+64*6+9+14+15]\n", - " queen_mobility = weights[5+64*6+9+14+15:5+64*6+9+14+15+28]\n", - " # Create the plots. First, plot the psqt. To do this, we need to:\n", - " # Add the material values to the pst (excluding the king).\n", - " pst[0, :] += material[0]\n", - " pst[1, :] += material[1]\n", - " pst[2, :] += material[2]\n", - " pst[3, :] += material[3]\n", - " pst[4, :] += material[4]\n", - " # Now plot the pst.\n", - " fig, axs = plt.subplots(2, 3)\n", - " # Make the figure bigger using figure() method.\n", - " fig.set_size_inches(18.5, 10.5)\n", - " fig.suptitle(\"Piece Square Tables\")\n", - " for i in range(6):\n", - " axs[i//3, i%3].imshow(pst[i].reshape(8, 8), cmap='hot', interpolation='nearest')\n", - " axs[i//3, i%3].set_title(\"Piece: \" + str(i))\n", - " # Add the value text to the plot.\n", - " for y in range(8):\n", - " for x in range(8):\n", - " axs[i//3, i%3].text(x, y, str(round(pst[i, y*8 + x].item())), color='black', ha='center', va='center')\n", - " plt.show()\n", - " # Now show the mobility features. For each piece, plot the mobility features using a bar plot.\n", - " fig, axs = plt.subplots(2, 2)\n", - " fig.set_size_inches(12.5, 6.5)\n", - " fig.suptitle(\"Piece Mobility Features\")\n", - " axs[0, 0].bar(range(9), knight_mobility)\n", - " axs[0, 0].set_title(\"Knight Mobility\")\n", - " axs[0, 1].bar(range(14), bishop_mobility)\n", - " axs[0, 1].set_title(\"Bishop Mobility\")\n", - " axs[1, 0].bar(range(15), rook_mobility)\n", - " axs[1, 0].set_title(\"Rook Mobility\")\n", - " axs[1, 1].bar(range(28), queen_mobility)\n", - " axs[1, 1].set_title(\"Queen Mobility\")\n", - " # Add the value text to the plot.\n", - " for i in range(9):\n", - " axs[0, 0].text(i, knight_mobility[i], str(round(knight_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " for i in range(14):\n", - " axs[0, 1].text(i, bishop_mobility[i], str(round(bishop_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " for i in range(15):\n", - " axs[1, 0].text(i, rook_mobility[i], str(round(rook_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " for i in range(28):\n", - " axs[1, 1].text(i, queen_mobility[i], str(round(queen_mobility[i].item())), color='black', ha='center', va='bottom')\n", - " plt.show()\n", - " \n", - "\n", - "\n", - "\n", - "visualize(model)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Print the final weights. Print the weights rounded to 2 decimal places.\n", - "p = 5+64*6+9+14+15+28\n", - "newliners = [\n", - " 5, 5+64*1,5+64*2,5+64*3,5+64*4,5+64*5,5+64*6, 5+64*6+9, 5+64*6+9+14, 5+64*6+9+14+15, 5+64*6+9+14+15+28,\n", - " p+1, p+2, p+3, p+4, p+5, p+6, p+7, p+8,\n", - " p+15, p+16, p+17, p+18, p+19, p+20\n", - "]\n", - "\n", - "\n", - "\n", - "def psqtprint(numbers, s):# Determine the maximum width of the numbers\n", - " max_width = 4\n", - " \n", - " # Print the numbers with proper formatting\n", - " for i in range(0, len(numbers), 8):\n", - " row = numbers[i:i+8]\n", - " formatted_row = ', '.join(f'{round(num - s):>{max_width}}' for num in row)\n", - " print(f' {formatted_row} ,')\n", - "\n", - "\n", - "weights = model.mgfc.weight.data[0]\n", - "stuff = []\n", - "s = []\n", - "for i in range(len(weights)):\n", - " # print(f\"{round(weights[i].item())}\", end=\", \")\n", - " s.append(weights[i].item())\n", - " if i+1 in newliners:\n", - " # print()\n", - " stuff.append(s)\n", - " s = []\n", - "stuff.append(s)\n", - "\n", - "heads = [\"const Score\",\"constexpr Score\"]\n", - "\n", - "names = [\"mgValues\", \"mgPawnTable\", \"mgKnightTable\", \"mgBishopTable\", \"mgRookTable\", \"mgQueenTable\", \"mgKingTable\", \"knightMobMg\", \"bishopMobMg\", \"rookMobMg\", \"queenMobMg\",\n", - " \"DOUBLEISOLATEDPENMG\", \"ISOLATEDPENMG\", \"BACKWARDPENMG\", \"DOUBLEDPENMG\", \"SUPPORTEDPHALANXMG\", \"ADVANCABLEPHALANXMG\", \"R_SUPPORTEDPHALANXMG\", \"R_ADVANCABLEPHALANXMG\",\n", - " \"passedRankBonusMg\", \"PASSEDPATHBONUSMG\", \"SUPPORTEDPASSERMG\", \"INNERSHELTERMG\", \"OUTERSHELTERMG\", \"BISHOPPAIRMG\", \"ROOKONOPENFILEMG\", \"ROOKONSEMIOPENFILEMG\", \"TEMPOMG\"]\n", - "\n", - "for i in range(len(stuff)):\n", - " item = stuff[i] \n", - " if len(item)==64:\n", - " print(heads[0]+\" \"+names[i]+\" [\"+str(len(item))+\"] = {\\n\")\n", - " psqtprint(item, stuff[0][i-1] if i < 6 else 0)\n", - " print(\"\\n};\")\n", - " elif len(item)>1:\n", - " print(heads[0]+\" \"+names[i]+\" [\"+str(len(item))+\"] = {\",end = \"\")\n", - " for x in item:\n", - " print(round(x),end=\", \")\n", - " print(\"};\")\n", - " else:\n", - " print(heads[1]+\" \"+names[i]+\" = \"+str(round(item[0]))+\";\")\n", - " \n", - "\n", - "weights = model.egfc.weight.data[0]\n", - "stuff = []\n", - "s = []\n", - "for i in range(len(weights)):\n", - " # print(f\"{round(weights[i].item())}\", end=\", \")\n", - " s.append(weights[i].item())\n", - " if i+1 in newliners:\n", - " # print()\n", - " stuff.append(s)\n", - " s = []\n", - "stuff.append(s)\n", - "\n", - "heads = [\"const Score\",\"constexpr Score\"]\n", - "\n", - "nameseg = [\"egValues\", \"egPawnTable\", \"egKnightTable\", \"egBishopTable\", \"egRookTable\", \"egQueenTable\", \"egKingTable\", \"knightMobEg\", \"bishopMobEg\", \"rookMobEg\", \"queenMobEg\",\n", - " \"DOUBLEISOLATEDPENEG\", \"ISOLATEDPENEG\", \"BACKWARDPENEG\", \"DOUBLEDPENEG\", \"SUPPORTEDPHALANXEG\", \"ADVANCABLEPHALANXEG\", \"R_SUPPORTEDPHALANXEG\", \"R_ADVANCABLEPHALANXEG\",\n", - " \"passedRankBonusEg\", \"PASSEDPATHBONUSEG\", \"SUPPORTEDPASSEREG\", \"INNERSHELTEREG\", \"OUTERSHELTEREG\", \"BISHOPPAIREG\", \"ROOKONOPENFILEEG\", \"ROOKONSEMIOPENFILEEG\", \"TEMPOEG\"]\n", - "\n", - "for i in range(len(stuff)):\n", - " item = stuff[i] \n", - " if len(item)==64:\n", - " print(heads[0]+\" \"+nameseg[i]+\" [\"+str(len(item))+\"] = {\\n\")\n", - " psqtprint(item, stuff[0][i-1] if i < 6 else 0)\n", - " print(\"\\n};\")\n", - " elif len(item)>1:\n", - " print(heads[0]+\" \"+nameseg[i]+\" [\"+str(len(item))+\"] = {\",end = \"\")\n", - " for x in item:\n", - " print(round(x),end=\", \")\n", - " print(\"};\")\n", - " else:\n", - " print(heads[1]+\" \"+nameseg[i]+\" = \"+str(round(item[0]))+\";\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define the list of numbers\n", - "numbers = [\n", - "-71, -40, -35, -4, -12, -3, -9, -85, -9, 32, 30, 14, 30, 38, 31, 0, -3, 28, 42, 55, 50, 66, 48, 8, -7, 22, 45, 57, 59, 57, 40, 12, -24, 18, 33, 58, 53, 41, 30, 1, -27, 2, 18, 30, 28, 21, 10, -5, -43, -8, -7, 5, 9, 1, -12, -35, -80, -61, -38, -26, -38, -28, -53, -89, \n", - "]\n", - "\n", - "# Determine the maximum width of the numbers\n", - "max_width = max(len(str(num)) for num in numbers)\n", - "\n", - "# Print the numbers with proper formatting\n", - "for i in range(0, len(numbers), 8):\n", - " row = numbers[i:i+8]\n", - " formatted_row = ', '.join(f'{num:>{max_width}}' for num in row)\n", - " print(f' {formatted_row} ,')\n", - "\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/zobrist.cpp b/src/zobrist.cpp deleted file mode 100644 index 5d97272..0000000 --- a/src/zobrist.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "zobrist.h" -#include "random.h" - -// random piece keys -HashKey pieceKeysTable[12][64]; -HashKey pawnKeysTable[12][64]; -HashKey nonPawnKeysTable[12][64]; -// random enPassant keys -HashKey enPassantKeysTable[65]; -// random castling keys -HashKey castleKeysTable[16]; -// random side key -HashKey sideKey; -/** - * @brief The initHashKeys function initializes the random keys. - */ -void initHashKeys(){ - state = 1804289383; - for(int i = 0; i < 12; i++){ - for(int j = 0; j < 64; j++){ - pieceKeysTable[i][j] = getRandom64(); - switch (i % 6){ - case 0: - pawnKeysTable[i][j] = pieceKeysTable[i][j]; - nonPawnKeysTable[i][j] = 0; - break; - case 1: case 2: - pawnKeysTable[i][j] = 0; - nonPawnKeysTable[i][j] = pieceKeysTable[i][j]; - break; - case 3: - pawnKeysTable[i][j] = 0; - nonPawnKeysTable[i][j] = pieceKeysTable[i][j]; - break; - case 4: - pawnKeysTable[i][j] = 0; - nonPawnKeysTable[i][j] = pieceKeysTable[i][j]; - break; - case 5: - pawnKeysTable[i][j] = 0; - nonPawnKeysTable[i][j] = pieceKeysTable[i][j]; - break; - } - } - } - for(int i = 0; i < 64; i++){ - enPassantKeysTable[i] = getRandom64(); - } - enPassantKeysTable[64] = 0; // So that hashing a "no en passant" will return the same hashKey as before the move - for(int i = 0; i < 16; i++){ - castleKeysTable[i] = getRandom64(); - } - sideKey = getRandom64(); -} \ No newline at end of file diff --git a/src/zobrist.h b/src/zobrist.h deleted file mode 100644 index 48f616e..0000000 --- a/src/zobrist.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "types.h" - -// random piece keys -extern HashKey pieceKeysTable[12][64]; -extern HashKey pawnKeysTable[12][64]; -extern HashKey nonPawnKeysTable[12][64]; -// random enPassant keys -extern HashKey enPassantKeysTable[65]; -// random castling keys -extern HashKey castleKeysTable[16]; -// random side key -extern HashKey sideKey; - -/** - * @brief The initHashKeys function initializes the random keys. - */ -void initHashKeys(); \ No newline at end of file diff --git a/utils/spsa_utils/constants_sub.py b/utils/spsa_utils/constants_sub.py deleted file mode 100644 index c731312..0000000 --- a/utils/spsa_utils/constants_sub.py +++ /dev/null @@ -1,39 +0,0 @@ -import re - -def load_new_values(mapping_file): - """Load new parameter values from the mapping file.""" - new_values = {} - with open(mapping_file, 'r') as f: - for line in f: - parts = line.strip().split(',') - if len(parts) == 2: - param, value = parts[0].strip(), parts[1].strip() - new_values[param] = value - return new_values - -def update_tune_params(input_file, output_file, mapping_file): - """Update the first number argument in TUNE_PARAM or NO_TUNE_PARAM based on the mapping.""" - new_values = load_new_values(mapping_file) - - # allow optional + or - in the old value - pattern = re.compile( - r'^(.*?\b(TUNE_PARAM|NO_TUNE_PARAM)\((\w+),\s*)' # prefix up to first value - r'([+-]?\d+)' # capture signed integer - r'(,.*)$' # rest of the line - ) - - with open(input_file, 'r') as f: - lines = f.readlines() - - with open(output_file, 'w') as f_out: - for line in lines: - m = pattern.match(line) - if m: - prefix, _, param_name, old_value, suffix = m.groups() - if param_name in new_values: - new_val = new_values[param_name] - line = f"{prefix}{new_val}{suffix}\n" - f_out.write(line) - -# Example usage -update_tune_params('original.txt', 'output.txt', 'spsa_out.txt') diff --git a/utils/spsa_utils/original.txt b/utils/spsa_utils/original.txt deleted file mode 100644 index 731b793..0000000 --- a/utils/spsa_utils/original.txt +++ /dev/null @@ -1,122 +0,0 @@ -// History stuff -TUNE_PARAM(maxHistoryBonus, 2140, 1, 4096, 128, 0.002); -TUNE_PARAM(historyBonusQuadDepth, 8, 1, 32, 1, 0.002); -TUNE_PARAM(historyBonusLinDepth, 198, 1, 1024, 16, 0.002); -TUNE_PARAM(historyBonusOffset, -271, -1024, 1024, 52, 0.002); - -TUNE_PARAM(maxHistoryMalus, 822, 1, 4096, 128, 0.002); -TUNE_PARAM(historyMalusQuadDepth, 5, 1, 32, 1, 0.002); -TUNE_PARAM(historyMalusLinDepth, 259, 1, 1024, 16, 0.002); -TUNE_PARAM(historyMalusOffset, -4, -1024, 1024, 52, 0.002); - -// LMR table values -TUNE_PARAM(lmrDepthValue, 995, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrMoveValue, 1072, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrA0, 721, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrC0, -310, -1000, 1000, 100, 0.002); -TUNE_PARAM(lmrA1, 764, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrC1, 722, 500, 1500, 50, 0.002); - -// LMR additionals -TUNE_PARAM(lmrCieckA, 4331, 2048, 8192, 256, 0.002) -TUNE_PARAM(lmrCieckB, 1465, 500, 2500, 98, 0.002) -TUNE_PARAM(lmrCieckC, 688, 128, 1024, 48, 0.002) -TUNE_PARAM(lmrPV, 1136, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrExpectedDecent, 682, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrQuietHistoryDivisor, 8418, 2000, 14000, 500, 0.002) -TUNE_PARAM(lmrQuietCutNode, 1947, 250, 2750, 125, 0.002); -TUNE_PARAM(lmrQuietTTPV, 1028, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrBadNoisyCutNode, 730, 250, 2750, 125, 0.002); -TUNE_PARAM(lmrNoisyHistoryDivisorA, 5556, 2000, 14000, 500, 0.002) -TUNE_PARAM(lmrNoisyHistoryDivisorB, 6877, 2000, 14000, 500, 0.002) - -// Deeper / shallower -TUNE_PARAM(doDeeperMargin, 33, 10, 50, 2, 0.002) - -// PVS SEE -TUNE_PARAM(pvsSeeThresholdNoisy, -21, -160, -10, 6, 0.002) -TUNE_PARAM(pvsSeeThresholdQuiet, -112, -160, -10, 6, 0.002) -NO_TUNE_PARAM(pvsSeeMaxDepth, 7, 5, 10, 0.5, 0.002) - -// LMP values -TUNE_PARAM(lmpA0, 631, 250, 1750, 64, 0.002); -TUNE_PARAM(lmpC0, 1712, 500, 5000, 198, 0.002); -TUNE_PARAM(lmpA1, 1020, 250, 1750, 64, 0.002); -TUNE_PARAM(lmpC1, 2946, 500, 5000, 198, 0.002); - -// RFP values -TUNE_PARAM(futilityMarginDelta, 100, 45, 145, 4, 0.002); -NO_TUNE_PARAM(RFPDepth, 8, 5, 10, .5, 0.002); - -// NMP values -TUNE_PARAM(nmpMarginBias, 176, 100, 300, 8, 0.002); -TUNE_PARAM(nmpDepthMargin, 26, 10, 50, 2, 0.002); -NO_TUNE_PARAM(nmpDepthDivisor, 4, 2, 6, .5, 0.002); -TUNE_PARAM(nmpScoreDivisor, 221, 100, 300, 8, 0.002); -NO_TUNE_PARAM(nmpQ1, 3, 1, 5, .5, 0.002); -NO_TUNE_PARAM(nmpQ2, 3, 0, 5, .5, 0.002); - -// Razoring value -TUNE_PARAM(razorQ1, 97, -200, 200, 16, 0.002); -TUNE_PARAM(razorQ2, 228, 100, 500, 16, 0.002); -NO_TUNE_PARAM(razorDepth, 3, 2, 5, .5, 0.002); - -// Singular Extensions -TUNE_PARAM(singularDepthMultiplier, 8, 1, 30, 1, 0.002); -TUNE_PARAM(doubleExtensionMargin, 24, 1, 50, 2, 0.002); -NO_TUNE_PARAM(singularSearchDepth, 7, 5, 10, .5, 0.002); - -// History Pruning values -TUNE_PARAM(historyPruningMultiplier, -1514, -5120, -1024, 205, 0.002); -TUNE_PARAM(historyPruningBias, 63, -2048, 2048, 205, 0.002); - -// IIR values -NO_TUNE_PARAM(IIRDepth, 6, 3, 8, .5, 0.002); - -// FFP values -TUNE_PARAM(futPruningMultiplier, 49, 30, 130, 4, 0.002); -TUNE_PARAM(futPruningAdd, 246, 150, 350, 8, 0.002); -NO_TUNE_PARAM(futPruningDepth, 9, 6, 10, 0.5, 0.002); -TUNE_PARAM(qsFutilityMargin, 82, 0, 150, 8, 0.002) - -// Move ordering values -TUNE_PARAM(captScoreMvvMultiplier, 13, 8, 32, 1, 0.002) - -// Time management values -TUNE_PARAM(timeTmA, 140, 10, 200, 2, 0.002) -TUNE_PARAM(timeTmB, 990, 0, 1000, 13, 0.002) -TUNE_PARAM(timeTmOptimScale, 404, 100, 1000, 11, 0.002) -TUNE_PARAM(nodesTmMax, 1867, 1500, 2500, 13, 0.002) -TUNE_PARAM(nodesTmMul, 1356, 750, 1500, 10, 0.002) - -// CorrHist scale values -TUNE_PARAM(MAXCORRHISTUNSCALED, 38, 16, 128, 8, 0.002) -TUNE_PARAM(MAXCORRHISTMILLIUPDATE, 205, 128, 512, 18, 0.002) - -// CorrHist correction values -TUNE_PARAM(pawnCorrWeight, 1213, 0, 2048, 102, 0.002) -TUNE_PARAM(nonPawnCorrWeight, 1032, 0, 2048, 102, 0.002) -TUNE_PARAM(T0CorrWeight, 1117, 0, 2048, 102, 0.002) -TUNE_PARAM(T1CorrWeight, 857, 0, 2048, 102, 0.002) -TUNE_PARAM(T2CorrWeight, 1008, 0, 2048, 102, 0.002) -TUNE_PARAM(T3CorrWeight, 1044, 0, 2048, 102, 0.002) -TUNE_PARAM(T4CorrWeight, 1071, 0, 2048, 102, 0.002) -TUNE_PARAM(T5CorrWeight, 915, 0, 2048, 102, 0.002) -TUNE_PARAM(T6CorrWeight, 1144, 0, 2048, 102, 0.002) -TUNE_PARAM(T7CorrWeight, 1028, 0, 2048, 102, 0.002) -TUNE_PARAM(T8CorrWeight, 934, 0, 2048, 102, 0.002) -TUNE_PARAM(T9CorrWeight, 1202, 0, 2048, 102, 0.002) - -// CorrHist update values -TUNE_PARAM(pawnCorrUpdate, 1077, 0, 2048, 102, 0.002) -TUNE_PARAM(nonPawnCorrUpdate, 1051, 0, 2048, 102, 0.002) -TUNE_PARAM(T0CorrUpdate, 938, 0, 2048, 102, 0.002) -TUNE_PARAM(T1CorrUpdate, 986, 0, 2048, 102, 0.002) -TUNE_PARAM(T2CorrUpdate, 976, 0, 2048, 102, 0.002) -TUNE_PARAM(T3CorrUpdate, 1045, 0, 2048, 102, 0.002) -TUNE_PARAM(T4CorrUpdate, 1114, 0, 2048, 102, 0.002) -TUNE_PARAM(T5CorrUpdate, 1002, 0, 2048, 102, 0.002) -TUNE_PARAM(T6CorrUpdate, 949, 0, 2048, 102, 0.002) -TUNE_PARAM(T7CorrUpdate, 1033, 0, 2048, 102, 0.002) -TUNE_PARAM(T8CorrUpdate, 1180, 0, 2048, 102, 0.002) -TUNE_PARAM(T9CorrUpdate, 878, 0, 2048, 102, 0.002) \ No newline at end of file diff --git a/utils/spsa_utils/output.txt b/utils/spsa_utils/output.txt deleted file mode 100644 index c5136cc..0000000 --- a/utils/spsa_utils/output.txt +++ /dev/null @@ -1,122 +0,0 @@ -// History stuff -TUNE_PARAM(maxHistoryBonus, 2272, 1, 4096, 128, 0.002); -TUNE_PARAM(historyBonusQuadDepth, 9, 1, 32, 1, 0.002); -TUNE_PARAM(historyBonusLinDepth, 216, 1, 1024, 16, 0.002); -TUNE_PARAM(historyBonusOffset, -340, -1024, 1024, 52, 0.002); - -TUNE_PARAM(maxHistoryMalus, 710, 1, 4096, 128, 0.002); -TUNE_PARAM(historyMalusQuadDepth, 4, 1, 32, 1, 0.002); -TUNE_PARAM(historyMalusLinDepth, 266, 1, 1024, 16, 0.002); -TUNE_PARAM(historyMalusOffset, 26, -1024, 1024, 52, 0.002); - -// LMR table values -TUNE_PARAM(lmrDepthValue, 1011, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrMoveValue, 1128, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrA0, 697, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrC0, -324, -1000, 1000, 100, 0.002); -TUNE_PARAM(lmrA1, 752, 500, 1500, 50, 0.002); -TUNE_PARAM(lmrC1, 763, 500, 1500, 50, 0.002); - -// LMR additionals -TUNE_PARAM(lmrCieckA, 4401, 2048, 8192, 256, 0.002) -TUNE_PARAM(lmrCieckB, 1489, 500, 2500, 98, 0.002) -TUNE_PARAM(lmrCieckC, 741, 128, 1024, 48, 0.002) -TUNE_PARAM(lmrPV, 1169, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrExpectedDecent, 694, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrQuietHistoryDivisor, 8396, 2000, 14000, 500, 0.002) -TUNE_PARAM(lmrQuietCutNode, 1978, 250, 2750, 125, 0.002); -TUNE_PARAM(lmrQuietTTPV, 980, 250, 2750, 125, 0.002) -TUNE_PARAM(lmrBadNoisyCutNode, 648, 250, 2750, 125, 0.002); -TUNE_PARAM(lmrNoisyHistoryDivisorA, 5192, 2000, 14000, 500, 0.002) -TUNE_PARAM(lmrNoisyHistoryDivisorB, 6587, 2000, 14000, 500, 0.002) - -// Deeper / shallower -TUNE_PARAM(doDeeperMargin, 33, 10, 50, 2, 0.002) - -// PVS SEE -TUNE_PARAM(pvsSeeThresholdNoisy, -16, -160, -10, 6, 0.002) -TUNE_PARAM(pvsSeeThresholdQuiet, -109, -160, -10, 6, 0.002) -NO_TUNE_PARAM(pvsSeeMaxDepth, 7, 5, 10, 0.5, 0.002) - -// LMP values -TUNE_PARAM(lmpA0, 597, 250, 1750, 64, 0.002); -TUNE_PARAM(lmpC0, 1929, 500, 5000, 198, 0.002); -TUNE_PARAM(lmpA1, 1023, 250, 1750, 64, 0.002); -TUNE_PARAM(lmpC1, 2795, 500, 5000, 198, 0.002); - -// RFP values -TUNE_PARAM(futilityMarginDelta, 99, 45, 145, 4, 0.002); -NO_TUNE_PARAM(RFPDepth, 8, 5, 10, .5, 0.002); - -// NMP values -TUNE_PARAM(nmpMarginBias, 177, 100, 300, 8, 0.002); -TUNE_PARAM(nmpDepthMargin, 26, 10, 50, 2, 0.002); -NO_TUNE_PARAM(nmpDepthDivisor, 4, 2, 6, .5, 0.002); -TUNE_PARAM(nmpScoreDivisor, 222, 100, 300, 8, 0.002); -NO_TUNE_PARAM(nmpQ1, 3, 1, 5, .5, 0.002); -NO_TUNE_PARAM(nmpQ2, 3, 0, 5, .5, 0.002); - -// Razoring value -TUNE_PARAM(razorQ1, 97, -200, 200, 16, 0.002); -TUNE_PARAM(razorQ2, 239, 100, 500, 16, 0.002); -NO_TUNE_PARAM(razorDepth, 3, 2, 5, .5, 0.002); - -// Singular Extensions -TUNE_PARAM(singularDepthMultiplier, 8, 1, 30, 1, 0.002); -TUNE_PARAM(doubleExtensionMargin, 21, 1, 50, 2, 0.002); -NO_TUNE_PARAM(singularSearchDepth, 7, 5, 10, .5, 0.002); - -// History Pruning values -TUNE_PARAM(historyPruningMultiplier, -1508, -5120, -1024, 205, 0.002); -TUNE_PARAM(historyPruningBias, 157, -2048, 2048, 205, 0.002); - -// IIR values -NO_TUNE_PARAM(IIRDepth, 6, 3, 8, .5, 0.002); - -// FFP values -TUNE_PARAM(futPruningMultiplier, 49, 30, 130, 4, 0.002); -TUNE_PARAM(futPruningAdd, 254, 150, 350, 8, 0.002); -NO_TUNE_PARAM(futPruningDepth, 9, 6, 10, 0.5, 0.002); -TUNE_PARAM(qsFutilityMargin, 77, 0, 150, 8, 0.002) - -// Move ordering values -TUNE_PARAM(captScoreMvvMultiplier, 14, 8, 32, 1, 0.002) - -// Time management values -TUNE_PARAM(timeTmA, 141, 10, 200, 2, 0.002) -TUNE_PARAM(timeTmB, 989, 0, 1000, 13, 0.002) -TUNE_PARAM(timeTmOptimScale, 420, 100, 1000, 11, 0.002) -TUNE_PARAM(nodesTmMax, 1867, 1500, 2500, 13, 0.002) -TUNE_PARAM(nodesTmMul, 1359, 750, 1500, 10, 0.002) - -// CorrHist scale values -TUNE_PARAM(MAXCORRHISTUNSCALED, 39, 16, 128, 8, 0.002) -TUNE_PARAM(MAXCORRHISTMILLIUPDATE, 193, 128, 512, 18, 0.002) - -// CorrHist correction values -TUNE_PARAM(pawnCorrWeight, 1310, 0, 2048, 102, 0.002) -TUNE_PARAM(nonPawnCorrWeight, 1128, 0, 2048, 102, 0.002) -TUNE_PARAM(T0CorrWeight, 1160, 0, 2048, 102, 0.002) -TUNE_PARAM(T1CorrWeight, 885, 0, 2048, 102, 0.002) -TUNE_PARAM(T2CorrWeight, 1003, 0, 2048, 102, 0.002) -TUNE_PARAM(T3CorrWeight, 1125, 0, 2048, 102, 0.002) -TUNE_PARAM(T4CorrWeight, 1230, 0, 2048, 102, 0.002) -TUNE_PARAM(T5CorrWeight, 873, 0, 2048, 102, 0.002) -TUNE_PARAM(T6CorrWeight, 1116, 0, 2048, 102, 0.002) -TUNE_PARAM(T7CorrWeight, 934, 0, 2048, 102, 0.002) -TUNE_PARAM(T8CorrWeight, 1013, 0, 2048, 102, 0.002) -TUNE_PARAM(T9CorrWeight, 1173, 0, 2048, 102, 0.002) - -// CorrHist update values -TUNE_PARAM(pawnCorrUpdate, 1061, 0, 2048, 102, 0.002) -TUNE_PARAM(nonPawnCorrUpdate, 1054, 0, 2048, 102, 0.002) -TUNE_PARAM(T0CorrUpdate, 828, 0, 2048, 102, 0.002) -TUNE_PARAM(T1CorrUpdate, 877, 0, 2048, 102, 0.002) -TUNE_PARAM(T2CorrUpdate, 1016, 0, 2048, 102, 0.002) -TUNE_PARAM(T3CorrUpdate, 1047, 0, 2048, 102, 0.002) -TUNE_PARAM(T4CorrUpdate, 1124, 0, 2048, 102, 0.002) -TUNE_PARAM(T5CorrUpdate, 1042, 0, 2048, 102, 0.002) -TUNE_PARAM(T6CorrUpdate, 903, 0, 2048, 102, 0.002) -TUNE_PARAM(T7CorrUpdate, 1106, 0, 2048, 102, 0.002) -TUNE_PARAM(T8CorrUpdate, 1248, 0, 2048, 102, 0.002) -TUNE_PARAM(T9CorrUpdate, 924, 0, 2048, 102, 0.002) diff --git a/utils/spsa_utils/spsa_out.txt b/utils/spsa_utils/spsa_out.txt deleted file mode 100644 index b63bf3a..0000000 --- a/utils/spsa_utils/spsa_out.txt +++ /dev/null @@ -1,77 +0,0 @@ -maxHistoryBonus, 2272 -historyBonusQuadDepth, 9 -historyBonusLinDepth, 216 -historyBonusOffset, -340 -maxHistoryMalus, 710 -historyMalusQuadDepth, 4 -historyMalusLinDepth, 266 -historyMalusOffset, 26 -lmrDepthValue, 1011 -lmrMoveValue, 1128 -lmrA0, 697 -lmrC0, -324 -lmrA1, 752 -lmrC1, 763 -lmrCieckA, 4401 -lmrCieckB, 1489 -lmrCieckC, 741 -lmrPV, 1169 -lmrExpectedDecent, 694 -lmrQuietHistoryDivisor, 8396 -lmrQuietCutNode, 1978 -lmrQuietTTPV, 980 -lmrBadNoisyCutNode, 648 -lmrNoisyHistoryDivisorA, 5192 -lmrNoisyHistoryDivisorB, 6587 -doDeeperMargin, 33 -pvsSeeThresholdNoisy, -16 -pvsSeeThresholdQuiet, -109 -lmpA0, 597 -lmpC0, 1929 -lmpA1, 1023 -lmpC1, 2795 -futilityMarginDelta, 99 -nmpMarginBias, 177 -nmpDepthMargin, 26 -nmpScoreDivisor, 222 -razorQ1, 97 -razorQ2, 239 -singularDepthMultiplier, 8 -doubleExtensionMargin, 21 -historyPruningMultiplier, -1508 -historyPruningBias, 157 -futPruningMultiplier, 49 -futPruningAdd, 254 -qsFutilityMargin, 77 -captScoreMvvMultiplier, 14 -timeTmA, 141 -timeTmB, 989 -timeTmOptimScale, 420 -nodesTmMax, 1867 -nodesTmMul, 1359 -MAXCORRHISTUNSCALED, 39 -MAXCORRHISTMILLIUPDATE, 193 -pawnCorrWeight, 1310 -nonPawnCorrWeight, 1128 -T0CorrWeight, 1160 -T1CorrWeight, 885 -T2CorrWeight, 1003 -T3CorrWeight, 1125 -T4CorrWeight, 1230 -T5CorrWeight, 873 -T6CorrWeight, 1116 -T7CorrWeight, 934 -T8CorrWeight, 1013 -T9CorrWeight, 1173 -pawnCorrUpdate, 1061 -nonPawnCorrUpdate, 1054 -T0CorrUpdate, 828 -T1CorrUpdate, 877 -T2CorrUpdate, 1016 -T3CorrUpdate, 1047 -T4CorrUpdate, 1124 -T5CorrUpdate, 1042 -T6CorrUpdate, 903 -T7CorrUpdate, 1106 -T8CorrUpdate, 1248 -T9CorrUpdate, 924 \ No newline at end of file