diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..a470cc0
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,44 @@
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: Consecutive
+AlignConsecutiveDeclarations: Consecutive
+AlignEscapedNewlines: DontAlign
+AlignOperands: AlignAfterOperator
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortEnumsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+BreakTemplateDeclarations: Yes
+BasedOnStyle: WebKit
+BitFieldColonSpacing: After
+BinPackParameters: false
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterFunction: false
+ AfterClass: false
+ AfterControlStatement: true
+ BeforeElse: true
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+BreakStringLiterals: false
+ColumnLimit: 100
+ContinuationIndentWidth: 2
+Cpp11BracedListStyle: true
+IndentGotoLabels: false
+IndentPPDirectives: BeforeHash
+IndentWidth: 4
+MaxEmptyLinesToKeep: 2
+NamespaceIndentation: None
+PackConstructorInitializers: Never
+ReflowComments: false
+SortIncludes: false
+SortUsingDeclarations: false
+SpaceAfterCStyleCast: true
+SpaceAfterTemplateKeyword: false
+SpaceBeforeCaseColon: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeInheritanceColon: false
+SpaceInEmptyBlock: false
+SpacesBeforeTrailingComments: 2
diff --git a/.gitignore b/.gitignore
index a54deda..bce9de6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,12 @@
# Ignore everything
-*
-
-# But not these directories and files
-!*.cpp
-!*.hpp
-!*.h
-!Makefile
-!README.md
-!LICENSE
-!.gitignore
-!CMakeLists.txt
\ No newline at end of file
+!COPYING
+src/*.nnue
+src/*.o
+src/cppchess_engine
+!src/*.cpp
+!src/*.hpp
+!src/*.h
+!src/layers/*
+!src/features/half_ka_v2_hm.cpp
+!src/features/half_ka_v2_hm.h
+!scripts
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..39f8ea5
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,80 @@
+{
+ "files.associations": {
+ "cmath": "cpp",
+ "array": "cpp",
+ "bitset": "cpp",
+ "cwchar": "cpp",
+ "unordered_map": "cpp",
+ "vector": "cpp",
+ "exception": "cpp",
+ "fstream": "cpp",
+ "functional": "cpp",
+ "initializer_list": "cpp",
+ "iosfwd": "cpp",
+ "istream": "cpp",
+ "new": "cpp",
+ "sstream": "cpp",
+ "stdexcept": "cpp",
+ "tuple": "cpp",
+ "any": "cpp",
+ "atomic": "cpp",
+ "hash_map": "cpp",
+ "bit": "cpp",
+ "cctype": "cpp",
+ "charconv": "cpp",
+ "chrono": "cpp",
+ "clocale": "cpp",
+ "codecvt": "cpp",
+ "compare": "cpp",
+ "complex": "cpp",
+ "concepts": "cpp",
+ "condition_variable": "cpp",
+ "cstdarg": "cpp",
+ "cstddef": "cpp",
+ "cstdint": "cpp",
+ "cstdio": "cpp",
+ "cstdlib": "cpp",
+ "cstring": "cpp",
+ "ctime": "cpp",
+ "cwctype": "cpp",
+ "deque": "cpp",
+ "forward_list": "cpp",
+ "list": "cpp",
+ "map": "cpp",
+ "set": "cpp",
+ "string": "cpp",
+ "unordered_set": "cpp",
+ "algorithm": "cpp",
+ "iterator": "cpp",
+ "memory": "cpp",
+ "memory_resource": "cpp",
+ "numeric": "cpp",
+ "optional": "cpp",
+ "random": "cpp",
+ "ratio": "cpp",
+ "string_view": "cpp",
+ "system_error": "cpp",
+ "type_traits": "cpp",
+ "utility": "cpp",
+ "format": "cpp",
+ "iomanip": "cpp",
+ "iostream": "cpp",
+ "limits": "cpp",
+ "mutex": "cpp",
+ "numbers": "cpp",
+ "ostream": "cpp",
+ "queue": "cpp",
+ "ranges": "cpp",
+ "semaphore": "cpp",
+ "span": "cpp",
+ "stop_token": "cpp",
+ "streambuf": "cpp",
+ "text_encoding": "cpp",
+ "thread": "cpp",
+ "cfenv": "cpp",
+ "cinttypes": "cpp",
+ "typeinfo": "cpp",
+ "valarray": "cpp",
+ "variant": "cpp"
+ }
+}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index 8f8f427..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-project(chess_engine)
-
-# Use C++17
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-# Optional: enable warnings (MSVC specific flags)
-if (MSVC)
- add_compile_options(/W4 /permissive-)
-else()
- add_compile_options(-Wall -Wextra -pedantic)
-endif()
-
-# Add the source files
-set(SOURCES
- main.cpp
- eval.cpp
- search.cpp
- tt.cpp
- movepick.cpp
- uci.cpp
- ucioptions.cpp
- timeman.cpp
-)
-
-# Define the executable
-add_executable(${PROJECT_NAME} ${SOURCES})
-
-# Threading support
-find_package(Threads REQUIRED)
-target_link_libraries(${PROJECT_NAME} Threads::Threads)
-
-# Platform-specific threading configurations
-if(WIN32)
- if(MSVC)
- # Windows with MSVC - uses Windows threading API
- target_compile_definitions(${PROJECT_NAME} PRIVATE WIN32_LEAN_AND_MEAN)
- elseif(MINGW)
- # MinGW on Windows - uses pthread
- target_compile_definitions(${PROJECT_NAME} PRIVATE _WIN32_WINNT=0x0601)
- # MinGW might need explicit pthread linking
- if(CMAKE_THREAD_LIBS_INIT)
- target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
- endif()
- endif()
-elseif(UNIX)
- # Unix/Linux systems - uses pthread
- if(CMAKE_THREAD_LIBS_INIT)
- target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
- endif()
- # Some older systems might need explicit -pthread flag
- if(CMAKE_USE_PTHREADS_INIT)
- target_compile_options(${PROJECT_NAME} PRIVATE -pthread)
- target_link_options(${PROJECT_NAME} PRIVATE -pthread)
- endif()
-endif()
-
-# Optional: Add atomic library support for older compilers
-if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9")
- target_link_libraries(${PROJECT_NAME} atomic)
-endif()
-
-# Set default build type if none is specified
-if(NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the build type (Debug, Release, etc.)" FORCE)
-endif()
-
-# Optional: Add specific compile flags per build type
-if(NOT MSVC)
- set(CMAKE_CXX_FLAGS_DEBUG "-g -march=native -mtune=native")
- set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -march=native -mtune=native -funroll-loops -ftree-vectorize -fomit-frame-pointer")
-else()
- set(CMAKE_CXX_FLAGS_DEBUG "/Zi /Od")
- set(CMAKE_CXX_FLAGS_RELEASE "/O2 /DNDEBUG")
-endif()
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 36d7111..0000000
--- a/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-# Compiler and Flags
-CXX = g++
-
-# Source files and object files
-SRC = main.cpp eval.cpp search.cpp tt.cpp movepick.cpp timeman.cpp uci.cpp ucioptions.cpp
-OBJ = $(SRC:.cpp=.o)
-
-# Output file
-EXEC = chess_engine
-
-# Default target: build the project
-all: $(EXEC)
-
-# Linking the object files into the executable
-$(EXEC): $(OBJ)
- $(CXX) $(LDFLAGS) -o $(EXEC) $(OBJ)
-
-# Rule to build object files from source files
-%.o: %.cpp
- $(CXX) $(CXXFLAGS) -std=c++17 -c $< -o $@
-
-# Clean up the compiled files
-clean:
- rm -f $(OBJ) $(EXEC)
-
-# To run the program after compilation
-run: $(EXEC)
- ./$(EXEC)
-
-# Rebuild the project
-rebuild: clean all
-
diff --git a/eval.cpp b/eval.cpp
deleted file mode 100644
index a0ba6cd..0000000
--- a/eval.cpp
+++ /dev/null
@@ -1,777 +0,0 @@
-#include "eval.hpp"
-#include
-#define EvaluationResult int16_t
-// 0. Evaluation result
-
-struct EvalBreakdown
-{
- EvaluationResult phase;
- EvaluationResult Material;
- EvaluationResult Doubled;
- EvaluationResult Isolated;
- EvaluationResult Backward;
- EvaluationResult Passed;
- EvaluationResult Center;
- EvaluationResult Mobility;
- EvaluationResult Shield;
- EvaluationResult KingTropism;
- EvaluationResult Space;
- EvaluationResult MGPSQT;
- EvaluationResult EGPSQT;
-};
-
-EvalBreakdown wEval{}, bEval{};
-// 1. Weights, in case of tuning (centipawns)
-// 1.1. Material weights
-constexpr int16_t PawnValue = 100, KnightValue = 325, BishopValue = 350, RookValue = 500, QueenValue = 900;
-// 1.2. Pawn structure
-constexpr int16_t Doubled = -100, Isolated = -80, Backward = -100, wpassed = 100, cpassed = 50,
- Center = 100;
-// 1.3. Mobility
-
-// Mobility weights per piece type
-constexpr int MOBILITY_WEIGHTS[] = {
- 0, // EMPTY / None
- 1, // PAWN (often ignored or handled separately)
- 4, // KNIGHT
- 4, // BISHOP
- 6, // ROOK
- 8, // QUEEN
- 0 // KING (usually ignored)
-};
-// 1.3. King safety
-constexpr int16_t pawnShield = 20, KingTropism = 5;
-// 1.4. Space
-constexpr int16_t Space = 10;
-// 1.5. Tempo
-constexpr int16_t Tempo = 28;
-// 1.6. PQST (source: Chessprogramming Wiki)
-// clang-format off
-int16_t mg_pawn_table[64] = {
- 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,
-};
-
-int16_t eg_pawn_table[64] = {
- 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,
-};
-
-int16_t mg_knight_table[64] = {
- -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,
-};
-
-int16_t eg_knight_table[64] = {
- -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,
-};
-
-int16_t mg_bishop_table[64] = {
- -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,
-};
-
-int16_t eg_bishop_table[64] = {
- -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,
-};
-
-int16_t mg_rook_table[64] = {
- 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,
-};
-
-int16_t eg_rook_table[64] = {
- 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,
-};
-
-int16_t mg_queen_table[64] = {
- -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,
-};
-
-int16_t eg_queen_table[64] = {
- -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,
-};
-
-int16_t mg_king_table[64] = {
- -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,
-};
-
-int16_t eg_king_table[64] = {
- -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
-};
-
-int16_t* mg_pesto_table[6] =
-{
- mg_pawn_table,
- mg_knight_table,
- mg_bishop_table,
- mg_rook_table,
- mg_queen_table,
- mg_king_table
-};
-
-int16_t* eg_pesto_table[6] =
-{
- eg_pawn_table,
- eg_knight_table,
- eg_bishop_table,
- eg_rook_table,
- eg_queen_table,
- eg_king_table
-};
-
-// clang-format on
-// 2. Evaluation functions
-// 2.1. Phase
-Evaluation int phase(const chess::Board &pos)
-{
- constexpr int KnightPhase = 1;
- constexpr int BishopPhase = 1;
- constexpr int RookPhase = 2;
- constexpr int QueenPhase = 4;
- constexpr int TotalPhase = KnightPhase * 4 + BishopPhase * 4 + RookPhase * 4 + QueenPhase * 2;
-
- int phase = (pos.pieces(chess::PieceType::KNIGHT, chess::Color::WHITE).count() +
- pos.pieces(chess::PieceType::KNIGHT, chess::Color::BLACK).count()) *
- KnightPhase +
- (pos.pieces(chess::PieceType::BISHOP, chess::Color::WHITE).count() +
- pos.pieces(chess::PieceType::BISHOP, chess::Color::BLACK).count()) *
- BishopPhase +
- (pos.pieces(chess::PieceType::ROOK, chess::Color::WHITE).count() +
- pos.pieces(chess::PieceType::ROOK, chess::Color::BLACK).count()) *
- RookPhase +
- (pos.pieces(chess::PieceType::QUEEN, chess::Color::WHITE).count() +
- pos.pieces(chess::PieceType::QUEEN, chess::Color::BLACK).count()) *
- QueenPhase;
-
- return wEval.phase = (phase * 256 + TotalPhase / 2) / TotalPhase;
-}
-// 2.2. Material (one-line) (all phases)
-AllPhases inline int16_t material(const chess::Board &pos)
-{ // Precompute piece counts (avoid multiple function calls)
- int pieceCount[10] = {
- pos.pieces(chess::PieceType::PAWN, chess::Color::WHITE).count(),
- pos.pieces(chess::PieceType::KNIGHT, chess::Color::WHITE).count(),
- pos.pieces(chess::PieceType::BISHOP, chess::Color::WHITE).count(),
- pos.pieces(chess::PieceType::ROOK, chess::Color::WHITE).count(),
- pos.pieces(chess::PieceType::QUEEN, chess::Color::WHITE).count(),
- pos.pieces(chess::PieceType::PAWN, chess::Color::BLACK).count(),
- pos.pieces(chess::PieceType::KNIGHT, chess::Color::BLACK).count(),
- pos.pieces(chess::PieceType::BISHOP, chess::Color::BLACK).count(),
- pos.pieces(chess::PieceType::ROOK, chess::Color::BLACK).count(),
- pos.pieces(chess::PieceType::QUEEN, chess::Color::BLACK).count(),
- };
- wEval.Material = pieceCount[0] * PawnValue + pieceCount[1] * KnightValue + pieceCount[2] * BishopValue +
- pieceCount[3] * RookValue + pieceCount[4] * QueenValue;
- bEval.Material = pieceCount[5] * PawnValue + pieceCount[6] * KnightValue + pieceCount[7] * BishopValue +
- pieceCount[8] * RookValue + pieceCount[9] * QueenValue;
- return wEval.Material - bEval.Material;
-}
-// 2.3. Pawn structure
-// 2.3.1. Doubled pawns
-Middlegame int16_t doubled(const chess::Board &pos)
-{
- wEval.Doubled = bEval.Doubled = 0;
- chess::Bitboard P = pos.pieces(chess::PieceType::PAWN, chess::Color::WHITE),
- p = pos.pieces(chess::PieceType::PAWN, chess::Color::BLACK);
- // We use bitwise tricks to avoid conditionals
- for (int i = 0; i < 8; ++i)
- {
- chess::Bitboard white = P & chess::attacks::MASK_FILE[i], black = p & chess::attacks::MASK_FILE[i];
- if (white.count() > 1)
- wEval.Doubled += (white.count() - 1) * Doubled;
- if (black.count() > 1)
- bEval.Doubled += (black.count() - 1) * Doubled;
- }
- return wEval.Doubled - bEval.Doubled;
-}
-// 2.3.2. Isolated pawns
-int16_t isolated(const chess::Board &pos)
-{
- chess::Bitboard P = pos.pieces(chess::PieceType::PAWN, chess::Color::WHITE);
- chess::Bitboard p = pos.pieces(chess::PieceType::PAWN, chess::Color::BLACK);
-
- constexpr chess::Bitboard noAFile = 0xFEFEFEFEFEFEFEFEULL; // mask out file A
- constexpr chess::Bitboard noHFile = 0x7F7F7F7F7F7F7F7FULL; // mask out file H
-
- chess::Bitboard adjP = ((P & noHFile) << 1) | ((P & noAFile) >> 1);
- chess::Bitboard adjp = ((p & noHFile) << 1) | ((p & noAFile) >> 1);
-
- chess::Bitboard Pi = P & ~adjP;
- chess::Bitboard pi = p & ~adjp;
-
- wEval.Isolated = Pi.count() * Isolated;
- bEval.Isolated = pi.count() * Isolated;
-
- return wEval.Isolated - bEval.Isolated;
-}
-
-// 2.3.3. Backward (https://www.chessprogramming.org/Backward_Pawns_(Bitboards))
-Middlegame inline int16_t backward(const chess::Board &pos)
-{
- chess::Bitboard P = pos.pieces(chess::PieceType::PAWN, chess::Color::WHITE),
- p = pos.pieces(chess::PieceType::PAWN, chess::Color::BLACK), wstop = P << 8, bstop = p << 8,
- wAttacks = chess::attacks::pawnLeftAttacks(P) |
- chess::attacks::pawnRightAttacks(P),
- bAttacks = chess::attacks::pawnLeftAttacks(p) |
- chess::attacks::pawnRightAttacks(p),
- wback = (wstop & bAttacks & ~wAttacks) >> 8, bback = (bstop & wAttacks & ~bAttacks) >> 8;
- wEval.Backward = wback.count() * Backward;
- bEval.Backward = bback.count() * Backward;
- return wEval.Backward - bEval.Backward;
-}
-// 2.3.4. Passed pawns (including candidate ones) (considered in both middlegame and endgame)
-
-AllPhases int16_t passed(const chess::Board &pos)
-{
- chess::Bitboard whitePawns = pos.pieces(chess::PieceType::PAWN, chess::Color::WHITE);
- chess::Bitboard blackPawns = pos.pieces(chess::PieceType::PAWN, chess::Color::BLACK);
-
- auto compute_score = [](chess::Bitboard P, chess::Bitboard p, bool isWhite) -> int16_t
- {
- chess::Bitboard mask = p;
- mask |= (p << 1 | p >> 1) & 0x6F6F6F6F6F6F6F6F; // ~FILE_A&~FILE_H
-
- if (isWhite)
- {
- mask |= (mask << 8);
- mask |= (mask << 16);
- mask |= (mask << 32);
- }
- else
- {
- mask |= (mask >> 8);
- mask |= (mask >> 16);
- mask |= (mask >> 32);
- }
-
- chess::Bitboard passed = P & ~mask;
- chess::Bitboard candidate = P & mask;
-
- return wpassed * passed.count() + cpassed * candidate.count();
- };
-
- wEval.Passed = compute_score(whitePawns, blackPawns, true);
- bEval.Passed = compute_score(blackPawns, whitePawns, false);
-
- return wEval.Passed - bEval.Passed;
-}
-
-Middlegame int16_t center(const chess::Board &pos)
-{
- const chess::Square centerSquares[] = {chess::Square::SQ_E4, chess::Square::SQ_D4, chess::Square::SQ_E5,
- chess::Square::SQ_D5};
-
- int w = 0, b = 0;
-
- for (chess::Square sq : centerSquares)
- {
- // Count attackers
- w += chess::attacks::attackers(pos, chess::Color::WHITE, sq).count();
- b += chess::attacks::attackers(pos, chess::Color::BLACK, sq).count();
- auto p = pos.at(sq);
- if (p.color() == chess::Color::WHITE)
- ++w;
- if (p.color() == chess::Color::BLACK)
- ++b;
- }
-
- wEval.Center = w * Center;
- bEval.Center = b * Center;
- return wEval.Center - bEval.Center;
-}
-/* Pawn cache */
-struct PawnEntry
-{
- uint64_t key; // Full pawn hash key (Zobrist)
- int16_t evalWhite; // Pawn eval score for White
- int16_t evalBlack; // Pawn eval score for Black
-};
-
-std::vector pawnHashTable(1 << 17);
-template
-AllPhases int pawn(const chess::Board &pos)
-{
- if (trace)
- {
- return doubled(pos) + isolated(pos) + backward(pos) + center(pos);
- }
- else
- {
- // what? Nah.
- auto a = pos.hash();
- auto entry = pawnHashTable[a & 131071];
- if (entry.key == a)
- return entry.evalWhite - entry.evalBlack;
- else
- {
- int16_t score = doubled(pos) + isolated(pos) + backward(pos) + center(pos);
- PawnEntry entry = {a,
- (int16_t)(wEval.Doubled + wEval.Isolated + wEval.Backward + wEval.Center),
- (int16_t)(bEval.Doubled + bEval.Isolated + bEval.Backward + bEval.Center)};
- pawnHashTable[a & 131071] = entry;
- return score;
- }
- }
-}
-// 2.4. Mobility
-AllPhases int16_t mobility(const chess::Board &board)
-{
- using namespace chess;
- Bitboard occupied = board.occ();
- int mobilityScore[2] = {0, 0};
- const Color sides[2] = {Color::WHITE, Color::BLACK};
-
- // Lookup table for attack functions per piece type
- auto attackFuncs = [](Square sq, Bitboard occ, PieceType pt) -> Bitboard
- {
- switch (pt)
- {
- case (int)PieceType::KNIGHT:
- return attacks::knight(sq);
- case (int)PieceType::BISHOP:
- return attacks::bishop(sq, occ);
- case (int)PieceType::ROOK:
- return attacks::rook(sq, occ);
- case (int)PieceType::QUEEN:
- return attacks::queen(sq, occ);
- default:
- return 0;
- }
- };
-
- for (Color side : sides)
- {
- Bitboard us = board.us(side);
-
- for (PieceType pt : {PieceType::KNIGHT, PieceType::BISHOP, PieceType::ROOK, PieceType::QUEEN})
- {
- int ptIndex = static_cast(pt);
- Bitboard pieces = board.pieces(pt) & us;
- while (pieces)
- {
- Square sq = pieces.pop();
- Bitboard attacks = attackFuncs(sq, occupied, pt);
- attacks &= ~us; // remove friendly squares
- mobilityScore[static_cast(side)] += MOBILITY_WEIGHTS[ptIndex] * attacks.count();
- }
- }
- }
-
- wEval.Mobility = mobilityScore[0];
- bEval.Mobility = mobilityScore[1];
- return mobilityScore[0] - mobilityScore[1];
-}
-
-// 2.5. King safety
-// 2.5.1. Pawn shield
-Middlegame int16_t pawn_shield(const chess::Board &board)
-{
- constexpr chess::Bitboard SHIELD = 0x00ff00000000ff00ULL; // rank 2 and 7 for pawn shield
- constexpr chess::Bitboard SHIELD2 = 0x0000ff0000ff0000ULL; // rank 3 and 6 for isolated pawns
- chess::Bitboard wkingAttacksBB = chess::attacks::king(board.kingSq(chess::Color::WHITE)),
- bKingAttacksBB = chess::attacks::king(board.kingSq(chess::Color::BLACK));
- int wshieldCount1 = (wkingAttacksBB & SHIELD).count(), wshieldCount2 = (wkingAttacksBB & SHIELD2).count();
- int bshieldCount1 = (bKingAttacksBB & SHIELD).count(), bshieldCount2 = (bKingAttacksBB & SHIELD2).count();
- wEval.Shield = (!wshieldCount1 * wshieldCount2 + wshieldCount1) * pawnShield;
- bEval.Shield = (!bshieldCount1 * bshieldCount2 + bshieldCount1) * pawnShield;
- return wEval.Shield - bEval.Shield;
-}
-
-Middlegame int16_t king_tropism(const chess::Board &board)
-{
- using namespace chess;
- const Square wKing = board.kingSq(Color::WHITE);
- const Square bKing = board.kingSq(Color::BLACK);
-
- int wScore = 0, bScore = 0;
-
- // Consider only attacking pieces
- for (PieceType pt : {PieceType::QUEEN, PieceType::ROOK, PieceType::BISHOP, PieceType::KNIGHT})
- {
- Bitboard whiteAttackers = board.pieces(pt, Color::WHITE);
- Bitboard blackAttackers = board.pieces(pt, Color::BLACK);
-
- while (whiteAttackers)
- {
- Square sq = whiteAttackers.pop();
- wScore += 7 - chess::Square::value_distance(sq, bKing); // closer = higher danger
- }
-
- while (blackAttackers)
- {
- Square sq = blackAttackers.pop();
- bScore += 7 - chess::Square::value_distance(sq, wKing);
- }
- }
-
- // Scale the result
- wEval.KingTropism = wScore * KingTropism;
- bEval.KingTropism = bScore * KingTropism;
-
- return wEval.KingTropism - bEval.KingTropism;
-}
-
-Middlegame inline int16_t king_safety(const chess::Board &board) { return pawn_shield(board) + king_tropism(board); }
-// 2.6. Space
-AllPhases int space(const chess::Board &board)
-{
- int spaceS[2] = {0, 0}; // [WHITE, BLACK]
-
- // Evaluate space control for both sides
- for (chess::Color color : {chess::Color::WHITE, chess::Color::BLACK})
- {
- chess::Color opponent = ~color;
-
- // Space Evaluation: Count controlled squares in the opponent's half
- chess::Bitboard my_pawns = board.pieces(chess::PieceType::PAWN, color);
-
- while (my_pawns)
- {
- chess::Square sq = my_pawns.pop();
- chess::Bitboard pawn_attacks = chess::attacks::pawn(color, sq);
-
- while (pawn_attacks)
- {
- chess::Square target = pawn_attacks.pop();
- // Check if square is in opponent's half
- bool in_opponent_half =
- (color == chess::Color::WHITE && target >= 32) || (color == chess::Color::BLACK && target < 32);
-
- if (in_opponent_half && !board.isAttacked(target, opponent) && !board.at(target))
- {
- spaceS[static_cast(color)]++;
- }
- }
- }
- }
- wEval.Space = spaceS[0] * Space;
- bEval.Space = spaceS[1] * Space;
- return wEval.Space - bEval.Space;
-}
-// 2.7. Tempo (simple) (all phases)
-AllPhases inline int16_t tempo(const chess::Board &board)
-{
- return (board.sideToMove() == chess::Color::WHITE) ? Tempo : -Tempo;
-}
-// 2.8. Endgame
-Endgame bool draw(const chess::Board &board)
-{
- // KPvK with Rule of the Square
- chess::Square wk = board.kingSq(chess::Color::WHITE), bk = board.kingSq(chess::Color::BLACK);
- chess::Bitboard p = board.pieces(chess::PieceType::PAWN);
- if (!board.hasNonPawnMaterial(chess::Color::WHITE) && !board.hasNonPawnMaterial(chess::Color::BLACK) && p.count() == 1)
- {
- chess::Square pawn = p.pop();
- auto c = board.at(pawn).color();
- chess::Square promoSq(pawn.file(), chess::Rank::rank(chess::Rank::RANK_8, c));
- if (chess::Square::value_distance((c ? bk : wk), promoSq) <= chess::Square::value_distance(pawn, promoSq))
- return 1;
- }
- return board.isInsufficientMaterial();
-}
-template
-AllPhases int16_t psqt_eval(const chess::Board &board)
-{
- auto pieces = board.us(chess::Color::WHITE);
-
- while (pieces)
- {
- int sq = pieces.pop();
- chess::PieceType piece = board.at(sq);
- if constexpr (Midgame)
- wEval.MGPSQT += mg_pesto_table[(int)piece][sq];
- else
- wEval.EGPSQT += eg_pesto_table[(int)piece][sq];
- }
- pieces = board.us(chess::Color::BLACK);
-
- while (pieces)
- {
- chess::Square sq = pieces.pop();
- chess::PieceType piece = board.at(sq);
- sq.flip();
- if constexpr (Midgame)
- bEval.MGPSQT += mg_pesto_table[(int)piece][sq.index()];
- else
- bEval.EGPSQT += eg_pesto_table[(int)piece][sq.index()];
- }
- if constexpr (Midgame)
- return wEval.MGPSQT - bEval.MGPSQT; // Negate for Black
- else
- return wEval.EGPSQT - bEval.EGPSQT; // Negate for Black
-}
-// huge table for distances, idk but it gives O(1) access
-static const unsigned char chebyshev_distance[64][64] = {
- {0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7, 5, 5, 5, 5, 5, 5, 6, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7},
- {1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 5, 5, 5, 5, 5, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7},
- {1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7, 5, 5, 5, 5, 5, 5, 6, 7, 6, 6, 6, 6, 6, 6, 6, 7},
- {1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6},
- {2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6},
- {3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6},
- {4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6},
- {5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6},
- {6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6},
- {7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 5, 5, 5, 5, 5, 7, 6, 6, 6, 6, 6, 6, 6},
- {2, 2, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7, 5, 5, 5, 5, 5, 5, 6, 7},
- {2, 2, 2, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5, 6},
- {2, 2, 2, 2, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5},
- {3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5},
- {4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5},
- {5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5},
- {6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 5, 5, 5, 5, 5, 5},
- {7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 5, 5, 5, 5, 5},
- {3, 3, 3, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7},
- {3, 3, 3, 3, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6},
- {3, 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5},
- {3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4},
- {4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4},
- {5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 4, 4, 4, 4, 4, 4},
- {6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 4, 4, 4, 4, 4},
- {7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 4, 4, 4, 4},
- {4, 4, 4, 4, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7},
- {4, 4, 4, 4, 4, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6},
- {4, 4, 4, 4, 4, 4, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5},
- {4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4},
- {4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3},
- {5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 3, 3, 3, 3, 3},
- {6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 3, 3, 3, 3},
- {7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 3, 3, 3},
- {5, 5, 5, 5, 5, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7},
- {5, 5, 5, 5, 5, 5, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6},
- {5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5},
- {5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4},
- {5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 2, 2, 2, 2, 3},
- {5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 2, 2, 2, 2},
- {6, 5, 5, 5, 5, 5, 5, 5, 6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 2, 2, 2},
- {7, 6, 5, 5, 5, 5, 5, 5, 7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 2, 2},
- {6, 6, 6, 6, 6, 6, 6, 7, 5, 5, 5, 5, 5, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7},
- {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6},
- {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5},
- {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4},
- {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3},
- {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2, 5, 4, 3, 2, 1, 1, 1, 2},
- {6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1, 6, 5, 4, 3, 2, 1, 1, 1},
- {7, 6, 6, 6, 6, 6, 6, 6, 7, 6, 5, 5, 5, 5, 5, 5, 7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 1},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 5, 5, 5, 5, 5, 5, 6, 7, 4, 4, 4, 4, 4, 5, 6, 7, 3, 3, 3, 3, 4, 5, 6, 7, 2, 2, 2, 3, 4, 5, 6, 7, 1, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 6, 4, 4, 4, 4, 4, 4, 5, 6, 3, 3, 3, 3, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 1, 1, 1, 2, 3, 4, 5, 6, 1, 0, 1, 2, 3, 4, 5, 6},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 3, 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, 2, 2, 3, 4, 5, 2, 1, 1, 1, 2, 3, 4, 5, 2, 1, 0, 1, 2, 3, 4, 5},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 4, 3, 2, 1, 1, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 3, 3, 3, 3, 3, 3, 5, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, 1, 1, 1, 2, 5, 4, 3, 2, 1, 0, 1, 2},
- {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 6, 5, 4, 4, 4, 4, 4, 4, 6, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 3, 2, 2, 2, 2, 6, 5, 4, 3, 2, 1, 1, 1, 6, 5, 4, 3, 2, 1, 0, 1},
- {7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 6, 5, 5, 5, 5, 5, 5, 7, 6, 5, 4, 4, 4, 4, 4, 7, 6, 5, 4, 3, 3, 3, 3, 7, 6, 5, 4, 3, 2, 2, 2, 7, 6, 5, 4, 3, 2, 1, 1, 7, 6, 5, 4, 3, 2, 1, 0}
-};
-inline int distance_to_corner(uint8_t sq){
- return std::min({chebyshev_distance[sq][0], // A1
- chebyshev_distance[sq][56], // A8
- chebyshev_distance[sq][7], // H1
- chebyshev_distance[sq][63]});// H8
-}
-inline int distance_from_center(uint8_t sq){
- return std::min({chebyshev_distance[sq][34], // E4
- chebyshev_distance[sq][35], // D4
- chebyshev_distance[sq][42], // E5
- chebyshev_distance[sq][43]});// D5
-}
-int mopUp(const chess::Board& pos) {
- chess::Square whiteKingSq = pos.kingSq(chess::Color::WHITE);
- chess::Square blackKingSq = pos.kingSq(chess::Color::BLACK);
-
- int whiteMaterial = wEval.Material;
- int blackMaterial = bEval.Material;
- int materialAdvantage = whiteMaterial - blackMaterial;
-
- // If neither side has a big material advantage, skip mop-up
- if (std::abs(materialAdvantage) < 300) return 0;
-
- if (wEval.phase>64) return 0;
-
- // Distance to corner for both kings
- int whiteCornerDist = distance_to_corner(whiteKingSq.index());
- int blackCornerDist = distance_to_corner(blackKingSq.index());
-
- // Distance from center for both kings
- int whiteCenterDist = distance_from_center(whiteKingSq.index());
- int blackCenterDist = distance_from_center(blackKingSq.index());
-
- // White mop-up score (push black king to corner, bring white king to center)
- int whiteMopUp = blackCornerDist * 4 - whiteCenterDist * 3;
-
- // Black mop-up score (push white king to corner, bring black king to center)
- int blackMopUp = whiteCornerDist * 4 - blackCenterDist * 3;
-
- // Return net mop-up score favoring White (+ means White advantage)
- return whiteMopUp - blackMopUp;
-}
-
-// 3. Main evaluation
-inline int16_t eg(const chess::Board &pos)
-{
- if (draw(pos))
- return 0;
- return space(pos) + tempo(pos) + material(pos) + passed(pos) + psqt_eval(pos) + mobility(pos) + king_safety(pos) + mopUp(pos);
-}
-template
-inline int16_t mg(const chess::Board &pos)
-{
- return material(pos) + space(pos) + tempo(pos) + mobility(pos) + king_safety(pos) + psqt_eval(pos) + pawn(pos);
-}
-struct CachedEvalEntry
-{
- uint64_t key; // Full pawn hash key (Zobrist)
- int16_t eval;
-};
-
-std::vector evalCache(1 << 17);
-template
-int16_t eval(const chess::Board &pos)
-{
- auto hash = pos.hash();
- auto &entry = evalCache[hash & 131071];
- if constexpr (!trace)
- if (entry.key == hash)
- return entry.eval;
- memset(&wEval, 0, sizeof(wEval));
- memset(&bEval, 0, sizeof(bEval));
- const int phase = ::phase(pos);
- const int sign = pos.sideToMove() == chess::Color::WHITE ? 1 : -1;
-
- int mgScore = mg(pos);
- int egScore = eg(pos);
- int finalScore = ((mgScore * phase) + (egScore * (256 - phase))) / 256 * sign;
-
- return finalScore;
-}
-int16_t eval(const chess::Board &pos)
-{
- return eval(pos);
-}
-void traceEvaluationResults(const char *label = nullptr, int16_t _eval = 0)
-{
- if (label)
- printf("\n[Trace: %s]\n", label);
-
- printf("+----------------+-------+-------+\n");
- printf("| Factor | White | Black |\n");
- printf("+----------------+-------+-------+\n");
- printf("| Phase | %13d |\n", wEval.phase);
- printf("| Material | %5d | %5d |\n", wEval.Material, bEval.Material);
- printf("| Doubled | %5d | %5d |\n", wEval.Doubled, bEval.Doubled);
- printf("| Isolated | %5d | %5d |\n", wEval.Isolated, bEval.Isolated);
- printf("| Backward | %5d | %5d |\n", wEval.Backward, bEval.Backward);
- printf("| Passed | %5d | %5d |\n", wEval.Passed, bEval.Passed);
- printf("| King tropism | %5d | %5d |\n", wEval.KingTropism, bEval.KingTropism);
- printf("| Center control | %5d | %5d |\n", wEval.Center, bEval.Center);
- printf("| Mobility | %5d | %5d |\n", wEval.Mobility, bEval.Mobility);
- printf("| Shield | %5d | %5d |\n", wEval.Shield, bEval.Shield);
- printf("| Space | %5d | %5d |\n", wEval.Space, bEval.Space);
- printf("| MiddlegamePSQT | %5d | %5d |\n", wEval.MGPSQT, bEval.MGPSQT);
- printf("| EndgamePSQT | %5d | %5d |\n", wEval.EGPSQT, bEval.EGPSQT);
- printf("| Total | %13d |\n", _eval);
- printf("+----------------+-------+-------+\n");
-}
-void trace(const chess::Board &pos) { traceEvaluationResults("Handcrafted", eval(pos)); }
-int16_t piece_value(chess::PieceType p)
-{
- switch ((int)p)
- {
- case (int)chess::PieceType::PAWN:
- return PawnValue;
- case (int)chess::PieceType::KNIGHT:
- return KnightValue;
- case (int)chess::PieceType::BISHOP:
- return BishopValue;
- case (int)chess::PieceType::ROOK:
- return RookValue;
- case (int)chess::PieceType::QUEEN:
- return QueenValue;
- default:
- return 0;
- }
-}
diff --git a/eval.hpp b/eval.hpp
deleted file mode 100644
index 08f98db..0000000
--- a/eval.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include "chess.hpp"
-#include
-#include
-
-constexpr int MAX_PLY = 64;
-constexpr int MAX_MATE = 32'000;
-constexpr int MAX_SCORE_CP = 31'000;
-inline int16_t MATE(int i) { return MAX_MATE - i; }
-inline int16_t MATE_DISTANCE(int16_t i) { return MAX_MATE - abs(i); }
-int16_t eval(const chess::Board &board);
-void trace(const chess::Board &board);
-int16_t piece_value(chess::PieceType);
-// some clarity for documentation
-#define Evaluation [[nodiscard]]
-#define AllPhases Evaluation
-#define Middlegame Evaluation
-#define Endgame Evaluation
diff --git a/main.cpp b/main.cpp
deleted file mode 100644
index 1ec23e2..0000000
--- a/main.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "chess.hpp"
-#include "search.hpp"
-#include "ucioptions.hpp"
-#include "uci.hpp"
-#include
-#include // for setbuf
-int main() {
- // Some quirks competition programming only for flushing buffers
- setbuf(stdout, NULL);
- UCIOptions::addSpin("Hash", 16, 1, 1024, [](const UCIOptions::Option& opt)->void {
- search::tt.resize(std::get(opt.value));
- });
- uci_loop();
- return 0;
-}
diff --git a/movepick.cpp b/movepick.cpp
deleted file mode 100644
index 74452c0..0000000
--- a/movepick.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-#include "movepick.hpp"
-
-namespace movepick
-{
- // 1. SEE
-
- // Return type changed to chess::Square for consistency
- chess::Square select_least_valuable(chess::Board &board, chess::Bitboard bb)
- {
- if (bb.empty())
- return chess::Square::NO_SQ; // Use NO_SQ sentinel for no square
-
- int least_value = 5000;
- chess::Square least_valuable_square = chess::Square::NO_SQ;
-
- while (bb)
- {
- int idx = bb.pop(); // idx is int index of bitboard square
- chess::Square sq(idx);
- int value = piece_value(board.at(sq));
- if (value < least_value)
- {
- least_value = value;
- least_valuable_square = sq;
- }
- }
- return least_valuable_square;
- }
-
- int SEE(chess::Board &board, chess::Move move)
- {
- constexpr int max_gain_size = MAX_PLY + 1; // To avoid overflow in gain[d + 1]
- std::array gain{};
- int d = 0;
- chess::Color side = board.sideToMove();
- chess::Bitboard occ = board.occ();
-
- chess::Square target_sq = move.to();
-
- // Initial gain setup:
- if (move.typeOf() & chess::Move::PROMOTION)
- {
- gain[0] = piece_value(move.promotionType());
- if (board.isCapture(move))
- gain[0] += piece_value(board.at(target_sq));
- }
- else if (move.typeOf() == chess::Move::ENPASSANT)
- {
- // We'll treat it normally below, so just assign captured pawn value now:
- gain[0] = piece_value(chess::PieceType::PAWN);
- }
- else
- {
- gain[0] = piece_value(board.at(target_sq));
- }
-
- chess::Square from_sq = move.from();
-
- // Remove the moving piece from occupancy:
- occ.clear(from_sq.index());
-
- // Special case for en passant: remove the captured pawn square here:
- if (move.typeOf() == chess::Move::ENPASSANT)
- {
- chess::Square ep_captured_sq(target_sq.file(), from_sq.rank()); // square behind target
- occ.clear(ep_captured_sq.index());
- }
-
- chess::Square next_attacker_sq = from_sq;
-
- while (++d < MAX_PLY)
- {
- side = ~side;
-
- // Find all attackers of target square from side to move:
- chess::Bitboard attackers = chess::attacks::attackers(board, side, target_sq) & occ;
-
- // Include x-ray attacks for sliding pieces:
- chess::Bitboard rook_attacks = chess::attacks::rook(target_sq, occ);
- chess::Bitboard bishop_attacks = chess::attacks::bishop(target_sq, occ);
-
- attackers |= rook_attacks & (board.pieces(chess::PieceType::ROOK, side) | board.pieces(chess::PieceType::QUEEN, side));
- attackers |= bishop_attacks & (board.pieces(chess::PieceType::BISHOP, side) | board.pieces(chess::PieceType::QUEEN, side));
-
- if (attackers.empty())
- break;
-
- next_attacker_sq = select_least_valuable(board, attackers);
- if (next_attacker_sq == chess::Square::NO_SQ)
- break;
-
- int captured_value = piece_value(board.at(next_attacker_sq));
- gain[d] = -gain[d - 1] + captured_value;
-
- if (std::max(-gain[d - 1], gain[d]) < 0)
- break;
-
- occ.clear(next_attacker_sq.index());
- }
-
- while (--d > 0)
- {
- gain[d] = std::max(-gain[d + 1], gain[d]);
- }
-
- return gain[0];
- }
-
- // 2. Killer moves
- chess::Move killerMoves[MAX_PLY][2] = {};
-
- void updateKillerMoves(chess::Move m, int ply)
- {
- if (killerMoves[ply][0] != m)
- {
- killerMoves[ply][1] = killerMoves[ply][0];
- killerMoves[ply][0] = m;
- }
- }
-
- // 3. History heuristic
- int historyHeuristic[64][64] = {}; // from-square to to-square
-
- void updateHistoryHeuristic(chess::Move m, int depth)
- {
- historyHeuristic[m.from().index()][m.to().index()] += depth * depth;
- }
-
- void orderMoves(chess::Board &board, chess::Movelist &moves, chess::Move ttMove, chess::Move pvMove, int ply)
- {
- for (auto &move : moves)
- {
- if (move == ttMove)
- move.setScore(10000);
- else if (move == pvMove)
- move.setScore(9000);
- else if (board.isCapture(move))
- move.setScore(SEE(board, move));
- else if (move == killerMoves[ply][0])
- move.setScore(8500);
- else if (move == killerMoves[ply][1])
- move.setScore(8000);
- else
- move.setScore(historyHeuristic[move.from().index()][move.to().index()]);
- }
- // Sort moves by score in descending order
- std::stable_sort(moves.begin(), moves.end(),
- [](const chess::Move &a, const chess::Move &b)
- { return a.score() > b.score(); });
- }
-
- void qOrderMoves(chess::Board &board, chess::Movelist &moves)
- {
- // clang-format off
- int16_t promotion_table[4][8] = {
- {-58, -38, -13, -28, -31, -27, -63, -99}, // N
- {-14, -21, -11, -8, -7, -9, -17, -24}, // B
- { 13, 10, 18, 15, 12, 12, 8, 5}, // R
- { -9, 22, 22, 27, 27, 19, 10, 20}, // Q
- };
- // clang-format on
-
- for (auto &move : moves)
- {
- if (board.isCapture(move)) // Simple MVV-LVA
- {
- move.setScore(SEE(board, move));
- }
- else if (move.typeOf() & chess::Move::PROMOTION)
- {
- int promoValue = piece_value(move.promotionType());
- int captureValue = board.isCapture(move) ? piece_value(board.at(move.to())) : 0;
- move.setScore(promoValue + captureValue + promotion_table[move.promotionType() - 1][move.to().file()]);
- }
- else
- {
- move.setScore(historyHeuristic[move.from().index()][move.to().index()]);
- }
- }
- // Sort moves by score in descending order
- std::stable_sort(moves.begin(), moves.end(),
- [](const chess::Move &a, const chess::Move &b)
- { return a.score() > b.score(); });
- }
-}
diff --git a/movepick.hpp b/movepick.hpp
deleted file mode 100644
index ce46757..0000000
--- a/movepick.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include "chess.hpp"
-#include "eval.hpp"
-namespace movepick
-{
- // Static Exchange Evaluation - evaluates material exchange on a square
- int SEE(chess::Board &, chess::Move);
- // Updates killer moves table for move ordering
- void updateKillerMoves(chess::Move, int);
- // Updates history heuristic table for move ordering
- void updateHistoryHeuristic(chess::Move, int);
- // Orders moves for regular search (with TT move, killers at given ply)
- void orderMoves(chess::Board &, chess::Movelist &, chess::Move, chess::Move, int);
- // Orders moves for quiescence search (captures/promotions)
- void qOrderMoves(chess::Board &, chess::Movelist &);
- // Killer moves table: [ply][slot] for move ordering heuristic
- extern chess::Move killerMoves[MAX_PLY][2];
-}
\ No newline at end of file
diff --git a/scripts/.gitattributes b/scripts/.gitattributes
new file mode 100644
index 0000000..dfdb8b7
--- /dev/null
+++ b/scripts/.gitattributes
@@ -0,0 +1 @@
+*.sh text eol=lf
diff --git a/scripts/get_native_properties.sh b/scripts/get_native_properties.sh
new file mode 100755
index 0000000..773d6c2
--- /dev/null
+++ b/scripts/get_native_properties.sh
@@ -0,0 +1,159 @@
+#!/bin/sh
+
+#
+# Returns properties of the native system.
+# best architecture as supported by the CPU
+# filename of the best binary uploaded as an artifact during CI
+#
+
+# Check if all the given flags are present in the CPU flags list
+check_flags() {
+ for flag; do
+ printf '%s\n' "$flags" | grep -q -w "$flag" || return 1
+ done
+}
+
+# Set the CPU flags list
+# remove underscores and points from flags, e.g. gcc uses avx512vnni, while some cpuinfo can have avx512_vnni, some systems use sse4_1 others sse4.1
+get_flags() {
+ flags=$(awk '/^flags[ \t]*:|^Features[ \t]*:/{gsub(/^flags[ \t]*:[ \t]*|^Features[ \t]*:[ \t]*|[_.]/, ""); line=$0} END{print line}' /proc/cpuinfo)
+}
+
+# Check for gcc march "znver1" or "znver2" https://en.wikichip.org/wiki/amd/cpuid
+check_znver_1_2() {
+ vendor_id=$(awk '/^vendor_id/{print $3; exit}' /proc/cpuinfo)
+ cpu_family=$(awk '/^cpu family/{print $4; exit}' /proc/cpuinfo)
+ [ "$vendor_id" = "AuthenticAMD" ] && [ "$cpu_family" = "23" ] && znver_1_2=true
+}
+
+# Set the file CPU loongarch64 architecture
+set_arch_loongarch64() {
+ if check_flags 'lasx'; then
+ true_arch='loongarch64-lasx'
+ elif check_flags 'lsx'; then
+ true_arch='lonngarch64-lsx'
+ else
+ true_arch='loongarch64'
+ fi
+}
+
+# Set the file CPU x86_64 architecture
+set_arch_x86_64() {
+ if check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then
+ true_arch='x86-64-vnni256'
+ elif check_flags 'avx512f' 'avx512bw'; then
+ true_arch='x86-64-avx512'
+ elif [ -z "${znver_1_2+1}" ] && check_flags 'bmi2'; then
+ true_arch='x86-64-bmi2'
+ elif check_flags 'avx2'; then
+ true_arch='x86-64-avx2'
+ elif check_flags 'sse41' && check_flags 'popcnt'; then
+ true_arch='x86-64-sse41-popcnt'
+ else
+ true_arch='x86-64'
+ fi
+}
+
+set_arch_ppc_64() {
+ if $(grep -q -w "altivec" /proc/cpuinfo); then
+ power=$(grep -oP -m 1 'cpu\t+: POWER\K\d+' /proc/cpuinfo)
+ if [ "0$power" -gt 7 ]; then
+ # VSX started with POWER8
+ true_arch='ppc-64-vsx'
+ else
+ true_arch='ppc-64-altivec'
+ fi
+ else
+ true_arch='ppc-64'
+ fi
+}
+
+# Check the system type
+uname_s=$(uname -s)
+uname_m=$(uname -m)
+case $uname_s in
+ 'Darwin') # Mac OSX system
+ case $uname_m in
+ 'arm64')
+ true_arch='apple-silicon'
+ file_arch='m1-apple-silicon'
+ ;;
+ 'x86_64')
+ flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.')
+ set_arch_x86_64
+ if [ "$true_arch" = 'x86-64-vnni256' ] || [ "$true_arch" = 'x86-64-avx512' ]; then
+ file_arch='x86-64-bmi2'
+ fi
+ ;;
+ esac
+ file_os='macos'
+ file_ext='tar'
+ ;;
+ 'Linux') # Linux system
+ get_flags
+ case $uname_m in
+ 'x86_64')
+ file_os='ubuntu'
+ check_znver_1_2
+ set_arch_x86_64
+ ;;
+ 'i686')
+ file_os='ubuntu'
+ true_arch='x86-32'
+ ;;
+ 'ppc64'*)
+ file_os='ubuntu'
+ set_arch_ppc_64
+ ;;
+ 'aarch64')
+ file_os='android'
+ true_arch='armv8'
+ if check_flags 'asimddp'; then
+ true_arch="$true_arch-dotprod"
+ fi
+ ;;
+ 'armv7'*)
+ file_os='android'
+ true_arch='armv7'
+ if check_flags 'neon'; then
+ true_arch="$true_arch-neon"
+ fi
+ ;;
+ 'loongarch64'*)
+ file_os='linux'
+ set_arch_loongarch64
+ ;;
+ *) # Unsupported machine type, exit with error
+ printf 'Unsupported machine type: %s\n' "$uname_m"
+ exit 1
+ ;;
+ esac
+ file_ext='tar'
+ ;;
+ 'MINGW'*'ARM64'*) # Windows ARM64 system with POSIX compatibility layer
+ # TODO: older chips might be armv8, but we have no good way to detect, /proc/cpuinfo shows x86 info
+ file_os='windows'
+ true_arch='armv8-dotprod'
+ file_ext='zip'
+ ;;
+ 'CYGWIN'*|'MINGW'*|'MSYS'*) # Windows x86_64system with POSIX compatibility layer
+ get_flags
+ check_znver_1_2
+ set_arch_x86_64
+ file_os='windows'
+ file_ext='zip'
+ ;;
+ *)
+ # Unknown system type, exit with error
+ printf 'Unsupported system type: %s\n' "$uname_s"
+ exit 1
+ ;;
+esac
+
+if [ -z "$file_arch" ]; then
+ file_arch=$true_arch
+fi
+
+file_name="stockfish-$file_os-$file_arch.$file_ext"
+
+printf '%s %s\n' "$true_arch" "$file_name"
diff --git a/scripts/net.sh b/scripts/net.sh
new file mode 100755
index 0000000..1aa1fbf
--- /dev/null
+++ b/scripts/net.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+wget_or_curl=$( (command -v wget > /dev/null 2>&1 && echo "wget -qO-") || \
+ (command -v curl > /dev/null 2>&1 && echo "curl -skL"))
+
+
+sha256sum=$( (command -v shasum > /dev/null 2>&1 && echo "shasum -a 256") || \
+ (command -v sha256sum > /dev/null 2>&1 && echo "sha256sum"))
+
+if [ -z "$sha256sum" ]; then
+ >&2 echo "sha256sum not found, NNUE files will be assumed valid."
+fi
+
+get_nnue_filename() {
+ grep "$1" evaluate.h | grep "#define" | sed "s/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/"
+}
+
+validate_network() {
+ # If no sha256sum command is available, assume the file is always valid.
+ if [ -n "$sha256sum" ] && [ -f "$1" ]; then
+ if [ "$1" != "nn-$($sha256sum "$1" | cut -c 1-12).nnue" ]; then
+ rm -f "$1"
+ return 1
+ fi
+ fi
+}
+
+fetch_network() {
+ _filename="$(get_nnue_filename "$1")"
+
+ if [ -z "$_filename" ]; then
+ >&2 echo "NNUE file name not found for: $1"
+ return 1
+ fi
+
+ if [ -f "$_filename" ]; then
+ if validate_network "$_filename"; then
+ echo "Existing $_filename validated, skipping download"
+ return
+ else
+ echo "Removing invalid NNUE file: $_filename"
+ fi
+ fi
+
+ if [ -z "$wget_or_curl" ]; then
+ >&2 printf "%s\n" "Neither wget or curl is installed." \
+ "Install one of these tools to download NNUE files automatically."
+ exit 1
+ fi
+
+ for url in \
+ "https://tests.stockfishchess.org/api/nn/$_filename" \
+ "https://github.com/official-stockfish/networks/raw/master/$_filename"; do
+ echo "Downloading from $url ..."
+ if $wget_or_curl "$url" > "$_filename"; then
+ if validate_network "$_filename"; then
+ echo "Successfully validated $_filename"
+ else
+ echo "Downloaded $_filename is invalid"
+ continue
+ fi
+ else
+ echo "Failed to download from $url"
+ fi
+ if [ -f "$_filename" ]; then
+ return
+ fi
+ done
+
+ # Download was not successful in the loop, return false.
+ >&2 echo "Failed to download $_filename"
+ return 1
+}
+
+fetch_network EvalFileDefaultNameBig && \
+fetch_network EvalFileDefaultNameSmall
diff --git a/search.cpp b/search.cpp
deleted file mode 100644
index 7ca18ff..0000000
--- a/search.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-#include "search.hpp"
-#include "timeman.hpp"
-#include
-#include
-#include
-#include
-#include
-
-namespace search
-{
- struct PV
- {
- int8_t cmove;
- chess::Move pv[MAX_PLY];
- };
-
- constexpr int LMR_BONUS = 2;
- std::atomic stop_requested(false);
- PV stablePV;
- TranspositionTable tt;
- int seldepth = 0;
-
- struct SearchAbortException : public std::exception
- {
- SearchAbortException() = default;
- };
-
- inline bool isMateScore(int16_t score)
- {
- return std::abs(score) > MAX_SCORE_CP;
- }
-
- int16_t adjustMateScore(int16_t score, int ply)
- {
- return isMateScore(score) ? (score > 0 ? score - ply : score + ply) : score;
- }
-
- int16_t restoreMateScore(int16_t score, int ply)
- {
- return isMateScore(score) ? (score > 0 ? score + ply : score - ply) : score;
- }
-
- int16_t quiescence(chess::Board &board, int16_t alpha, int16_t beta, int ply)
- {
- seldepth = std::max(seldepth, ply);
- if (timeman::check_time() || stop_requested.load(std::memory_order_relaxed))
- throw SearchAbortException();
-
- ++nodes;
-
- int16_t stand_pat = eval(board);
- if (stand_pat >= beta)
- return beta;
- if (alpha < stand_pat)
- alpha = stand_pat;
-
- chess::Movelist moves;
- chess::movegen::legalmoves(moves, board);
- if (moves.empty())
- return board.inCheck() ? -MATE(ply) : 0;
-
- chess::Movelist tacticalMoves;
- for (auto mv : moves)
- {
- if (board.isCapture(mv) || (mv.typeOf() & chess::Move::PROMOTION) || board.givesCheck(mv) != chess::CheckType::NO_CHECK)
- tacticalMoves.add(mv);
- }
-
- movepick::qOrderMoves(board, tacticalMoves);
- for (auto mv : tacticalMoves)
- {
- // --- BEGIN SEE FILTER ---
- int gain = mv.score(); // Or use precomputed SEE
- if (board.isCapture(mv) && gain < 0)
- continue;
- // --- END SEE FILTER ---
-
- // --- BEGIN DELTA PRUNING ---
- int margin = 50;
- if (stand_pat + gain + margin < alpha)
- continue;
- // --- END DELTA PRUNING ---
-
- board.makeMove(mv);
- int16_t score = -quiescence(board, -beta, -alpha, ply + 1);
- board.unmakeMove(mv);
-
- if (score >= beta)
- return beta;
- if (score > alpha)
- alpha = score;
- }
- return alpha;
- }
-
- int16_t alpha_beta(chess::Board &board, int depth, int16_t alpha, int16_t beta, int ply, PV *pv, int ext = 0)
- {
- pv->cmove = 0;
- if (timeman::check_time() || stop_requested.load(std::memory_order_relaxed))
- throw SearchAbortException();
-
- uint64_t h = board.hash();
- TTEntry *entry = tt.lookup(h);
- chess::Move hash_move = entry ? entry->bestMove : chess::Move::NULL_MOVE;
-
- if (entry && entry->hash == h && entry->depth() >= depth)
- {
- int16_t score = adjustMateScore(entry->score(), ply);
- if (entry->flag() == TTFlag::LOWERBOUND && score >= beta)
- return score;
- if (entry->flag() == TTFlag::UPPERBOUND && score <= alpha)
- return score;
- if (entry->flag() == TTFlag::EXACT)
- return score;
- }
-
- chess::Movelist moves;
- chess::movegen::legalmoves(moves, board);
- if (moves.empty())
- return board.inCheck() ? -MATE(ply) : 0;
-
- if (depth <= 0){
- ++nodes;
- return quiescence(board, alpha, beta, ply);
- }
-
- bool in_check = board.inCheck();
- int16_t evalScore = eval(board);
-
- // --- BEGIN RAZORING ---
- if (depth <= 2 && !in_check)
- {
- if (evalScore + 150 < alpha)
- return quiescence(board, alpha, beta, ply);
- }
- // --- END RAZORING ---
-
- bool can_do_null = (!in_check) && (depth >= 3);
- if (can_do_null)
- {
- board.makeNullMove();
- int R = depth / 6;
- int16_t score = -alpha_beta(board, depth - 1 - R, -beta, -beta + 1, ply + 1, pv);
- board.unmakeNullMove();
- if (score >= beta)
- {
- tt.store(h, chess::Move::NULL_MOVE, restoreMateScore(score, ply), depth, TTFlag::LOWERBOUND);
- return score;
- }
- }
-
- bool has_hash = (hash_move != chess::Move::NULL_MOVE);
- if (!has_hash && depth >= 4)
- {
- PV temp;
- temp.cmove = 0;
- alpha_beta(board, depth - 2, alpha, beta, ply, &temp);
- TTEntry *iid = tt.lookup(board.hash());
- if (iid && iid->bestMove != chess::Move::NULL_MOVE)
- hash_move = iid->bestMove;
- }
-
- movepick::orderMoves(board, moves, hash_move, stablePV.pv[0], ply);
-
- chess::Move best_move = chess::Move();
- int16_t best_score = -MATE(0);
-
- for (int i = 0; i < moves.size(); ++i)
- {
- chess::Move mv = moves[i];
- PV sub_pv;
- sub_pv.cmove = 0;
-
- bool isCap = board.isCapture(mv);
- bool do_lmr = (i > 0) && !isCap && !in_check;
- bool givesCheck = board.givesCheck(mv) != chess::CheckType::NO_CHECK;
- bool isPromo = mv.typeOf() & chess::Move::PROMOTION;
-
- // --- BEGIN FUTILITY PRUNING ---
- if (depth <= 3 && !in_check && !isCap && !isPromo && !givesCheck)
- {
- const int margin = 100 * depth;
- if (evalScore + margin <= alpha)
- continue;
- }
- // --- END FUTILITY PRUNING ---
-
- // --- BEGIN EXTENSIONS ---
- int extension = 0;
- if (givesCheck)
- extension = 1;
-
- if (board.at(mv.from()) == chess::PieceType::PAWN && (mv.to().rank() >= chess::Rank::RANK_6))
- {
- int rank = board.sideToMove() == chess::Color::WHITE ? (int)mv.to().rank() : 7 - mv.to().rank();
- if (rank >= 5)
- extension += 1;
- }
-
- if (moves.size() == 1)
- extension += 1;
-
- if (ext + extension > 16)
- extension = 0;
-
- int new_depth = depth - 1 + extension;
- // --- END EXTENSIONS ---
-
- board.makeMove(mv);
- int16_t score;
-
- if (do_lmr && !extension && depth >= 3)
- {
- score = -alpha_beta(board, new_depth - LMR_BONUS, -alpha - 1, -alpha, ply + 1, &sub_pv, ext);
- if (score > alpha)
- score = -alpha_beta(board, new_depth, -beta, -alpha, ply + 1, &sub_pv, ext);
- }
- else
- {
- if (i == 0)
- score = -alpha_beta(board, new_depth, -beta, -alpha, ply + 1, &sub_pv, ext + extension);
- else
- {
- score = -alpha_beta(board, new_depth, -alpha - 1, -alpha, ply + 1, &sub_pv, ext + extension);
- if (score > alpha)
- score = -alpha_beta(board, new_depth, -beta, -alpha, ply + 1, &sub_pv, ext + extension);
- }
- }
-
- board.unmakeMove(mv);
-
- if (score > best_score)
- {
- best_score = score;
- best_move = mv;
- if (score > alpha)
- {
- alpha = score;
- pv->pv[0] = mv;
- std::memcpy(&pv->pv[1], sub_pv.pv, sizeof(chess::Move) * sub_pv.cmove);
- pv->cmove = sub_pv.cmove + 1;
- }
- }
-
- if (score >= beta)
- {
- if (!isCap)
- {
- movepick::updateKillerMoves(mv, ply);
- movepick::updateHistoryHeuristic(mv, depth);
- }
- break;
- }
- }
-
- if (best_score != -MATE(0))
- {
- TTFlag flag = (best_score >= beta) ? TTFlag::LOWERBOUND
- : (best_score > alpha) ? TTFlag::EXACT
- : TTFlag::UPPERBOUND;
- tt.store(h, best_move, restoreMateScore(best_score, ply), depth, flag);
- }
-
- return best_score;
- }
-
- void run_search(const chess::Board &board, const TimeControl &tc)
- {
- nodes = 0, seldepth = 0;
- stop_requested.store(false, std::memory_order_relaxed);
- timeman::setLimits(tc);
-
- PV child_pv;
- child_pv.cmove = 0;
- stablePV.cmove = 0;
-
- chess::Movelist rootMoves;
- chess::movegen::legalmoves(rootMoves, board);
-
- int16_t last_score = 0;
- int max_iter = std::min(tc.infinite ? MAX_PLY : tc.depth, (int)MAX_PLY);
-
- for (int current_depth = 1; current_depth <= max_iter; ++current_depth)
- {
- chess::Board _board = board;
- child_pv.cmove = 0;
- int16_t alpha = last_score - 30;
- int16_t beta = last_score + 30;
-
- try
- {
- last_score = alpha_beta(_board, current_depth, alpha, beta, 0, &child_pv);
-
- if (last_score <= alpha || last_score >= beta)
- {
- alpha = -MATE(0);
- beta = MATE(0);
- last_score = alpha_beta(_board, current_depth, alpha, beta, 0, &child_pv);
- }
-
- stablePV = child_pv;
- auto elapsed = std::chrono::duration_cast(
- std::chrono::high_resolution_clock::now() - timeman::start_time)
- .count();
-
- if (isMateScore(last_score)){
- // Confusement: break
- printf("info depth %d seldepth %d nodes %" PRIu64 " nps %" PRIu64 " time %u score mate %d pv ",
- current_depth,
- seldepth,
- nodes.load(),
- (elapsed == 0 ? 0 : nodes.load() / elapsed * 1000),
- elapsed,
- last_score > 0 ? (MAX_MATE - last_score) : -(MAX_MATE + last_score));
- }
- else
- printf("info depth %d seldepth %d nodes %" PRIu64 " nps %" PRIu64 " time %u score cp %d pv ",
- current_depth,
- seldepth,
- nodes.load(),
- (elapsed == 0 ? 0 : nodes.load() / elapsed * 1000),
- elapsed,
- last_score);
-
- for (int j = 0; j < child_pv.cmove; ++j)
- printf("%s ", chess::uci::moveToUci(child_pv.pv[j], board.chess960()).c_str());
- printf("\n");
-
- // [DEBUG]
- if (isMateScore(last_score)) break;
- if (timeman::check_time())
- break;
- }
- catch (SearchAbortException &)
- {
- break;
- }
- }
-
- if (stablePV.cmove > 0)
- {
- printf("bestmove %s\n",
- chess::uci::moveToUci(stablePV.pv[0], board.chess960()).c_str());
- }
- else if (!rootMoves.empty())
- {
- printf("bestmove %s\n",
- chess::uci::moveToUci(rootMoves[0], board.chess960()).c_str());
- }
- else
- {
- printf("bestmove 0000\n");
- }
- }
-}
diff --git a/search.hpp b/search.hpp
deleted file mode 100644
index 0733daf..0000000
--- a/search.hpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-#include "chess.hpp"
-#include "timeman.hpp"
-#include "tt.hpp"
-#include "movepick.hpp"
-#include "eval.hpp"
-#include "ucioptions.hpp"
-#include
-#include
-#include
-namespace search
-{
- inline std::atomic nodes{0};
- void run_search(const chess::Board& board, const TimeControl& tc);
- extern std::atomic stop_requested;
- extern TranspositionTable tt;
-}
diff --git a/src/.depend b/src/.depend
new file mode 100644
index 0000000..2dfa530
--- /dev/null
+++ b/src/.depend
@@ -0,0 +1,105 @@
+half_ka_v2_hm.o: nnue/features/half_ka_v2_hm.cpp \
+ nnue/features/half_ka_v2_hm.h nnue/features/../../misc.h \
+ nnue/features/../../types.h nnue/features/../nnue_common.h \
+ nnue/features/../../misc.h nnue/features/../../bitboard.h \
+ nnue/features/../../types.h nnue/features/../../position.h \
+ nnue/features/../../chess.hpp \
+ nnue/features/../../nnue/nnue_accumulator.h \
+ nnue/features/../../nnue/../types.h \
+ nnue/features/../../nnue/nnue_architecture.h \
+ nnue/features/../../nnue/features/half_ka_v2_hm.h \
+ nnue/features/../../nnue/layers/affine_transform.h \
+ nnue/features/../../nnue/layers/../nnue_common.h \
+ nnue/features/../../nnue/layers/../simd.h \
+ nnue/features/../../nnue/layers/../../types.h \
+ nnue/features/../../nnue/layers/../nnue_common.h \
+ nnue/features/../../nnue/layers/affine_transform_sparse_input.h \
+ nnue/features/../../nnue/layers/../../bitboard.h \
+ nnue/features/../../nnue/layers/clipped_relu.h \
+ nnue/features/../../nnue/layers/sqr_clipped_relu.h \
+ nnue/features/../../nnue/nnue_common.h
+evaluate.o: evaluate.cpp evaluate.h types.h nnue/network.h \
+ nnue/../memory.h nnue/../types.h nnue/nnue_accumulator.h \
+ nnue/nnue_architecture.h nnue/features/half_ka_v2_hm.h \
+ nnue/features/../../misc.h nnue/features/../../types.h \
+ nnue/features/../nnue_common.h nnue/features/../../misc.h \
+ nnue/layers/affine_transform.h nnue/layers/../nnue_common.h \
+ nnue/layers/../simd.h nnue/layers/../../types.h \
+ nnue/layers/../nnue_common.h nnue/layers/affine_transform_sparse_input.h \
+ nnue/layers/../../bitboard.h nnue/layers/../../types.h \
+ nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h \
+ nnue/nnue_common.h nnue/nnue_feature_transformer.h nnue/../position.h \
+ nnue/../chess.hpp nnue/../types.h nnue/../nnue/nnue_accumulator.h \
+ nnue/simd.h nnue/nnue_misc.h nnue/nnue_misc.h position.h uci.hpp \
+ chess.hpp search.h movepick.hpp timeman.hpp tt.hpp memory.h \
+ ucioptions.hpp nnue/nnue_accumulator.h
+main.o: main.cpp search.h evaluate.h types.h movepick.hpp chess.hpp \
+ position.h nnue/nnue_accumulator.h nnue/../types.h \
+ nnue/nnue_architecture.h nnue/features/half_ka_v2_hm.h \
+ nnue/features/../../misc.h nnue/features/../../types.h \
+ nnue/features/../nnue_common.h nnue/features/../../misc.h \
+ nnue/layers/affine_transform.h nnue/layers/../nnue_common.h \
+ nnue/layers/../simd.h nnue/layers/../../types.h \
+ nnue/layers/../nnue_common.h nnue/layers/affine_transform_sparse_input.h \
+ nnue/layers/../../bitboard.h nnue/layers/../../types.h \
+ nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h \
+ nnue/nnue_common.h timeman.hpp tt.hpp memory.h nnue/network.h \
+ nnue/../memory.h nnue/nnue_accumulator.h nnue/nnue_feature_transformer.h \
+ nnue/../position.h nnue/simd.h nnue/nnue_misc.h uci.hpp ucioptions.hpp
+search.o: search.cpp search.h evaluate.h types.h movepick.hpp chess.hpp \
+ position.h nnue/nnue_accumulator.h nnue/../types.h \
+ nnue/nnue_architecture.h nnue/features/half_ka_v2_hm.h \
+ nnue/features/../../misc.h nnue/features/../../types.h \
+ nnue/features/../nnue_common.h nnue/features/../../misc.h \
+ nnue/layers/affine_transform.h nnue/layers/../nnue_common.h \
+ nnue/layers/../simd.h nnue/layers/../../types.h \
+ nnue/layers/../nnue_common.h nnue/layers/affine_transform_sparse_input.h \
+ nnue/layers/../../bitboard.h nnue/layers/../../types.h \
+ nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h \
+ nnue/nnue_common.h timeman.hpp tt.hpp memory.h nnue/network.h \
+ nnue/../memory.h nnue/nnue_accumulator.h nnue/nnue_feature_transformer.h \
+ nnue/../position.h nnue/simd.h nnue/nnue_misc.h
+timeman.o: timeman.cpp timeman.hpp types.h
+tt.o: tt.cpp tt.hpp chess.hpp types.h memory.h
+uci.o: uci.cpp uci.hpp chess.hpp search.h evaluate.h types.h movepick.hpp \
+ position.h nnue/nnue_accumulator.h nnue/../types.h \
+ nnue/nnue_architecture.h nnue/features/half_ka_v2_hm.h \
+ nnue/features/../../misc.h nnue/features/../../types.h \
+ nnue/features/../nnue_common.h nnue/features/../../misc.h \
+ nnue/layers/affine_transform.h nnue/layers/../nnue_common.h \
+ nnue/layers/../simd.h nnue/layers/../../types.h \
+ nnue/layers/../nnue_common.h nnue/layers/affine_transform_sparse_input.h \
+ nnue/layers/../../bitboard.h nnue/layers/../../types.h \
+ nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h \
+ nnue/nnue_common.h timeman.hpp tt.hpp memory.h nnue/network.h \
+ nnue/../memory.h nnue/nnue_accumulator.h nnue/nnue_feature_transformer.h \
+ nnue/../position.h nnue/simd.h nnue/nnue_misc.h ucioptions.hpp
+ucioptions.o: ucioptions.cpp ucioptions.hpp
+nnue_accumulator.o: nnue/nnue_accumulator.cpp nnue/nnue_accumulator.h \
+ nnue/../types.h nnue/nnue_architecture.h nnue/features/half_ka_v2_hm.h \
+ nnue/features/../../misc.h nnue/features/../../types.h \
+ nnue/features/../nnue_common.h nnue/features/../../misc.h \
+ nnue/layers/affine_transform.h nnue/layers/../nnue_common.h \
+ nnue/layers/../simd.h nnue/layers/../../types.h \
+ nnue/layers/../nnue_common.h nnue/layers/affine_transform_sparse_input.h \
+ nnue/layers/../../bitboard.h nnue/layers/../../types.h \
+ nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h \
+ nnue/nnue_common.h nnue/../bitboard.h nnue/../misc.h nnue/../position.h \
+ nnue/../chess.hpp nnue/../types.h nnue/../nnue/nnue_accumulator.h \
+ nnue/nnue_feature_transformer.h nnue/simd.h
+network.o: nnue/network.cpp nnue/network.h nnue/../memory.h \
+ nnue/../types.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \
+ nnue/features/half_ka_v2_hm.h nnue/features/../../misc.h \
+ nnue/features/../../types.h nnue/features/../nnue_common.h \
+ nnue/features/../../misc.h nnue/layers/affine_transform.h \
+ nnue/layers/../nnue_common.h nnue/layers/../simd.h \
+ nnue/layers/../../types.h nnue/layers/../nnue_common.h \
+ nnue/layers/affine_transform_sparse_input.h nnue/layers/../../bitboard.h \
+ nnue/layers/../../types.h nnue/layers/clipped_relu.h \
+ nnue/layers/sqr_clipped_relu.h nnue/nnue_common.h \
+ nnue/nnue_feature_transformer.h nnue/../position.h nnue/../chess.hpp \
+ nnue/../types.h nnue/../nnue/nnue_accumulator.h nnue/simd.h \
+ nnue/nnue_misc.h nnue/../incbin/incbin.h nnue/../evaluate.h \
+ nnue/../misc.h
+memory.o: memory.cpp memory.h
+movepick.o: movepick.cpp movepick.hpp chess.hpp types.h
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..4e18577
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,1128 @@
+#makefile of stockfish, but for cppchess_engine
+
+#Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+#Copyright(C) 2004 - 2025 The Stockfish developers(see AUTHORS file)
+#
+#Stockfish is free software : you can redistribute it and / or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation, either version 3 of the License, or
+#(at your option) any later version.
+#
+#Stockfish is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU General Public License
+#along with this program.If not, see < http: //www.gnu.org/licenses/>.
+
+
+### ==========================================================================
+### Section 1. General Configuration
+### ==========================================================================
+
+### Establish the operating system name
+KERNEL := $(shell uname -s)
+ifeq ($(KERNEL),Linux)
+ OS := $(shell uname -o)
+endif
+
+### Target Windows OS
+ifeq ($(OS),Windows_NT)
+ ifneq ($(COMP),ndk)
+ target_windows = yes
+ endif
+else ifeq ($(COMP),mingw)
+ target_windows = yes
+ ifeq ($(WINE_PATH),)
+ WINE_PATH := $(shell which wine)
+ endif
+endif
+
+### Executable name
+ifeq ($(target_windows),yes)
+ EXE = cppchess_engine.exe
+else
+ EXE = cppchess_engine
+endif
+
+### Installation dir definitions
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+
+### Built-in benchmark for pgo-builds
+PGOBENCH = $(WINE_PATH) ./$(EXE) bench
+
+### Source and object files
+SRCS = nnue/features/half_ka_v2_hm.cpp evaluate.cpp \
+ main.cpp search.cpp timeman.cpp tt.cpp uci.cpp \
+ ucioptions.cpp nnue/nnue_accumulator.cpp nnue/network.cpp \
+ memory.cpp movepick.cpp
+
+HEADERS = evaluate.h types.h movepick.hpp nnue/features/half_ka_v2_hm.h misc.h \
+ nnue/layers/affine_transform.h nnue/layers/affine_transform_sparse_input.h nnue/layers/clipped_relu.h \
+ nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \
+ nnue/nnue_common.h nnue/nnue_feature_transformer.h nnue/simd.h position.h search.h \
+ timeman.hpp tt.hpp types.h uci.hpp ucioptions.hpp nnue/network.h memory.h
+
+OBJS = $(SRCS:.cpp=.o)
+
+### ==========================================================================
+### Section 2. High-level Configuration
+### ==========================================================================
+#
+#flag-- - Comp switch -- -Description
+#-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+#
+#debug = yes / no-- - -DNDEBUG-- - Enable / Disable debug mode
+#sanitize = none / < sanitizer>...(-fsanitize)
+#-- -(undefined) -- - enable undefined behavior checks
+#-- -(thread) -- - enable threading error checks
+#-- -(address) -- - enable memory access checks
+#-- -... etc... -- - see compiler documentation for supported sanitizers
+#optimize = yes / no-- - (-O3 / -fast etc.)-- - Enable / Disable optimizations
+#arch = (name)-- - (-arch)-- - Target architecture
+#bits = 64 / 32 -- - -DIS_64BIT-- - 64 - / 32 - bit operating system
+#prefetch = yes / no-- - -DUSE_PREFETCH-- - Use prefetch asm - instruction
+#popcnt = yes / no-- - -DUSE_POPCNT-- - Use popcnt asm - instruction
+#pext = yes / no-- - -DUSE_PEXT-- - Use pext x86_64 asm - instruction
+#sse = yes / no-- - -msse-- - Use Intel Streaming SIMD Extensions
+#mmx = yes / no-- - -mmmx-- - Use Intel MMX instructions
+#sse2 = yes / no-- - -msse2-- - Use Intel Streaming SIMD Extensions 2
+#ssse3 = yes / no-- - -mssse3-- - Use Intel Supplemental Streaming SIMD Extensions 3
+#sse41 = yes / no-- - -msse4.1 -- -Use Intel Streaming SIMD Extensions 4.1
+#avx2 = yes / no-- - -mavx2-- - Use Intel Advanced Vector Extensions 2
+#avxvnni = yes / no-- - -mavxvnni-- - Use Intel Vector Neural Network Instructions AVX
+#avx512 = yes / no-- - -mavx512bw-- - Use Intel Advanced Vector Extensions 512
+#vnni256 = yes / no-- - -mavx256vnni-- \
+ - Use Intel Vector Neural Network Instructions 512 with 256bit operands
+#vnni512 = yes / no-- - -mavx512vnni-- - Use Intel Vector Neural Network Instructions 512
+#altivec = yes / no-- - -maltivec-- - Use PowerPC Altivec SIMD extension
+#vsx = yes / no-- - -mvsx-- - Use POWER VSX SIMD extension
+#neon = yes / no-- - -DUSE_NEON-- - Use ARM SIMD architecture
+#dotprod = yes / no-- - -DUSE_NEON_DOTPROD-- - Use ARM advanced SIMD Int8 dot product instructions
+#lsx = yes / no-- - -mlsx-- - Use Loongson SIMD eXtension
+#lasx = yes / no-- - -mlasx-- - use Loongson Advanced SIMD eXtension
+#
+#Note that Makefile is space sensitive, so when adding new architectures
+# or modifying existing flags, you have to make sure there are no extra spaces
+#at the end of the line for flag values.
+#
+#Example of use for these flags:
+#make build ARCH = x86 - 64 - avx512 debug = yes sanitize = "address undefined"
+
+
+### 2.1. General and architecture defaults
+
+ifeq ($(ARCH),)
+ ARCH = native
+endif
+
+ifeq ($(ARCH), native)
+ override ARCH := $(shell $(SHELL) ../scripts/get_native_properties.sh | cut -d " " -f 1)
+endif
+
+#explicitly check for the list of supported architectures(as listed with make help),
+#the user can override with `make ARCH = x86 - 32 - vnni256 SUPPORTED_ARCH = true`
+ifeq ($(ARCH), $(filter $(ARCH), \
+ x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \
+ x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
+ x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-64-altivec ppc-64-vsx ppc-32 e2k \
+ armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 \
+ loongarch64 loongarch64-lsx loongarch64-lasx))
+ SUPPORTED_ARCH=true
+else
+ SUPPORTED_ARCH=false
+endif
+
+optimize = yes
+debug = no
+sanitize = none
+bits = 64
+prefetch = no
+popcnt = no
+pext = no
+sse = no
+mmx = no
+sse2 = no
+ssse3 = no
+sse41 = no
+avx2 = no
+avxvnni = no
+avx512 = no
+vnni256 = no
+vnni512 = no
+altivec = no
+vsx = no
+neon = no
+dotprod = no
+arm_version = 0
+lsx = no
+lasx = no
+STRIP = strip
+
+ifneq ($(shell which clang-format-20 2> /dev/null),)
+ CLANG-FORMAT = clang-format-20
+else
+ CLANG-FORMAT = clang-format
+endif
+
+### 2.2 Architecture specific
+
+ifeq ($(findstring x86,$(ARCH)),x86)
+
+#x86 - 32 / 64
+
+ifeq ($(findstring x86-32,$(ARCH)),x86-32)
+ arch = i386
+ bits = 32
+ sse = no
+ mmx = yes
+else
+ arch = x86_64
+ sse = yes
+ sse2 = yes
+endif
+
+ifeq ($(findstring -sse,$(ARCH)),-sse)
+ sse = yes
+endif
+
+ifeq ($(findstring -popcnt,$(ARCH)),-popcnt)
+ popcnt = yes
+endif
+
+ifeq ($(findstring -mmx,$(ARCH)),-mmx)
+ mmx = yes
+endif
+
+ifeq ($(findstring -sse2,$(ARCH)),-sse2)
+ sse = yes
+ sse2 = yes
+endif
+
+ifeq ($(findstring -ssse3,$(ARCH)),-ssse3)
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+endif
+
+ifeq ($(findstring -sse41,$(ARCH)),-sse41)
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+endif
+
+ifeq ($(findstring -modern,$(ARCH)),-modern)
+ $(warning *** ARCH=$(ARCH) is deprecated, defaulting to ARCH=x86-64-sse41-popcnt. Execute `make help` for a list of available architectures. ***)
+ $(shell sleep 5)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+endif
+
+ifeq ($(findstring -avx2,$(ARCH)),-avx2)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ avx2 = yes
+endif
+
+ifeq ($(findstring -avxvnni,$(ARCH)),-avxvnni)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ avx2 = yes
+ avxvnni = yes
+ pext = yes
+endif
+
+ifeq ($(findstring -bmi2,$(ARCH)),-bmi2)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ avx2 = yes
+ pext = yes
+endif
+
+ifeq ($(findstring -avx512,$(ARCH)),-avx512)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ avx2 = yes
+ pext = yes
+ avx512 = yes
+endif
+
+ifeq ($(findstring -vnni256,$(ARCH)),-vnni256)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ avx2 = yes
+ pext = yes
+ vnni256 = yes
+endif
+
+ifeq ($(findstring -vnni512,$(ARCH)),-vnni512)
+ popcnt = yes
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ avx2 = yes
+ pext = yes
+ avx512 = yes
+ vnni512 = yes
+endif
+
+ifeq ($(sse),yes)
+ prefetch = yes
+endif
+
+# 64 - bit pext is not available on x86 - 32
+ifeq ($(bits),32)
+ pext = no
+endif
+
+else
+
+#all other architectures
+
+ifeq ($(ARCH),general-32)
+ arch = any
+ bits = 32
+endif
+
+ifeq ($(ARCH),general-64)
+ arch = any
+endif
+
+ifeq ($(ARCH),armv7)
+ arch = armv7
+ prefetch = yes
+ bits = 32
+ arm_version = 7
+endif
+
+ifeq ($(ARCH),armv7-neon)
+ arch = armv7
+ prefetch = yes
+ popcnt = yes
+ neon = yes
+ bits = 32
+ arm_version = 7
+endif
+
+ifeq ($(ARCH),armv8)
+ arch = armv8
+ prefetch = yes
+ popcnt = yes
+ neon = yes
+ arm_version = 8
+endif
+
+ifeq ($(ARCH),armv8-dotprod)
+ arch = armv8
+ prefetch = yes
+ popcnt = yes
+ neon = yes
+ dotprod = yes
+ arm_version = 8
+endif
+
+ifeq ($(ARCH),apple-silicon)
+ arch = arm64
+ prefetch = yes
+ popcnt = yes
+ neon = yes
+ dotprod = yes
+ arm_version = 8
+endif
+
+ifeq ($(ARCH),ppc-32)
+ arch = ppc
+ bits = 32
+endif
+
+ifeq ($(ARCH),ppc-64)
+ arch = ppc64
+ popcnt = yes
+ prefetch = yes
+endif
+
+ifeq ($(ARCH),ppc-64-altivec)
+ arch = ppc64
+ popcnt = yes
+ prefetch = yes
+ altivec = yes
+endif
+
+ifeq ($(ARCH),ppc-64-vsx)
+ arch = ppc64
+ popcnt = yes
+ prefetch = yes
+ vsx = yes
+endif
+
+ifeq ($(findstring e2k,$(ARCH)),e2k)
+ arch = e2k
+ mmx = yes
+ bits = 64
+ sse = yes
+ sse2 = yes
+ ssse3 = yes
+ sse41 = yes
+ popcnt = yes
+endif
+
+ifeq ($(ARCH),riscv64)
+ arch = riscv64
+endif
+
+ifeq ($(findstring loongarch64,$(ARCH)),loongarch64)
+ arch = loongarch64
+ prefetch = yes
+
+ifeq ($(findstring -lasx,$(ARCH)),-lasx)
+ lsx = yes
+ lasx = yes
+endif
+
+ifeq ($(findstring -lsx,$(ARCH)),-lsx)
+ lsx = yes
+endif
+
+endif
+endif
+
+
+### ==========================================================================
+### Section 3. Low-level Configuration
+### ==========================================================================
+
+### 3.1 Selecting compiler (default = gcc)
+ifeq ($(MAKELEVEL),0)
+ export ENV_CXXFLAGS := $(CXXFLAGS)
+ export ENV_DEPENDFLAGS := $(DEPENDFLAGS)
+ export ENV_LDFLAGS := $(LDFLAGS)
+endif
+
+CXXFLAGS = $(ENV_CXXFLAGS) -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS)
+DEPENDFLAGS = $(ENV_DEPENDFLAGS) -std=c++17
+LDFLAGS = $(ENV_LDFLAGS) $(EXTRALDFLAGS)
+
+ifeq ($(COMP),)
+ COMP=gcc
+endif
+
+ifeq ($(COMP),gcc)
+ comp=gcc
+ CXX=g++
+ CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations
+
+ ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
+ ifeq ($(OS),Android)
+ CXXFLAGS += -m$(bits)
+ LDFLAGS += -m$(bits)
+ endif
+ ifeq ($(ARCH),riscv64)
+ CXXFLAGS += -latomic
+ endif
+ else ifeq ($(arch),loongarch64)
+ CXXFLAGS += -latomic
+ else
+ CXXFLAGS += -m$(bits)
+ LDFLAGS += -m$(bits)
+ endif
+
+ ifeq ($(arch),$(filter $(arch),armv7))
+ LDFLAGS += -latomic
+ endif
+
+ ifneq ($(KERNEL),Darwin)
+ LDFLAGS += -Wl,--no-as-needed
+ endif
+endif
+
+ifeq ($(target_windows),yes)
+ LDFLAGS += -static
+endif
+
+ifeq ($(COMP),mingw)
+ comp=mingw
+
+ ifeq ($(bits),64)
+ ifeq ($(shell which x86_64-w64-mingw32-c++-posix 2> /dev/null),)
+ CXX=x86_64-w64-mingw32-c++
+ else
+ CXX=x86_64-w64-mingw32-c++-posix
+ endif
+ else
+ ifeq ($(shell which i686-w64-mingw32-c++-posix 2> /dev/null),)
+ CXX=i686-w64-mingw32-c++
+ else
+ CXX=i686-w64-mingw32-c++-posix
+ endif
+ endif
+ CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations
+endif
+
+ifeq ($(COMP),icx)
+ comp=icx
+ CXX=icpx
+ CXXFLAGS += --intel -pedantic -Wextra -Wshadow -Wmissing-prototypes \
+ -Wconditional-uninitialized -Wabi -Wdeprecated
+endif
+
+ifeq ($(COMP),clang)
+ comp=clang
+ CXX=clang++
+ ifeq ($(target_windows),yes)
+ CXX=x86_64-w64-mingw32-clang++
+ endif
+
+ CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-prototypes \
+ -Wconditional-uninitialized
+
+ ifeq ($(filter $(KERNEL),Darwin OpenBSD FreeBSD),)
+ ifeq ($(target_windows),)
+ ifneq ($(RTLIB),compiler-rt)
+ LDFLAGS += -latomic
+ endif
+ endif
+ endif
+
+ ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
+ ifeq ($(OS),Android)
+ CXXFLAGS += -m$(bits)
+ LDFLAGS += -m$(bits)
+ endif
+ ifeq ($(ARCH),riscv64)
+ CXXFLAGS += -latomic
+ endif
+ else ifeq ($(arch),loongarch64)
+ CXXFLAGS += -latomic
+ else
+ CXXFLAGS += -m$(bits)
+ LDFLAGS += -m$(bits)
+ endif
+endif
+
+ifeq ($(KERNEL),Darwin)
+ CXXFLAGS += -mmacosx-version-min=10.15
+ LDFLAGS += -mmacosx-version-min=10.15
+ ifneq ($(arch),any)
+ CXXFLAGS += -arch $(arch)
+ LDFLAGS += -arch $(arch)
+ endif
+ XCRUN = xcrun
+endif
+
+#To cross - compile for Android, use NDK version r27c or later.
+ifeq ($(COMP),ndk)
+ CXXFLAGS += -stdlib=libc++
+ comp=clang
+ ifeq ($(arch),armv7)
+ CXX=armv7a-linux-androideabi29-clang++
+ CXXFLAGS += -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=neon
+ ifneq ($(shell which arm-linux-androideabi-strip 2>/dev/null),)
+ STRIP=arm-linux-androideabi-strip
+ else
+ STRIP=llvm-strip
+ endif
+ endif
+ ifeq ($(arch),armv8)
+ CXX=aarch64-linux-android29-clang++
+ ifneq ($(shell which aarch64-linux-android-strip 2>/dev/null),)
+ STRIP=aarch64-linux-android-strip
+ else
+ STRIP=llvm-strip
+ endif
+ endif
+ ifeq ($(arch),x86_64)
+ CXX=x86_64-linux-android29-clang++
+ ifneq ($(shell which x86_64-linux-android-strip 2>/dev/null),)
+ STRIP=x86_64-linux-android-strip
+ else
+ STRIP=llvm-strip
+ endif
+ endif
+ LDFLAGS += -static-libstdc++
+endif
+
+### Allow overwriting CXX from command line
+ifdef COMPCXX
+ CXX=$(COMPCXX)
+endif
+
+#llvm - profdata must be version compatible with the specified CXX(be it clang, or the gcc alias)
+#make - j profile - build CXX = clang++ - 20 COMP = clang
+#Locate the version in the same directory as the compiler used,
+#with fallback to a generic one if it can't be located
+ LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))llvm-profdata
+ifeq ($(wildcard $(LLVM_PROFDATA)),)
+ LLVM_PROFDATA := llvm-profdata
+endif
+
+ifeq ($(comp),icx)
+ profile_make = icx-profile-make
+ profile_use = icx-profile-use
+else ifeq ($(comp),clang)
+ profile_make = clang-profile-make
+ profile_use = clang-profile-use
+else
+ profile_make = gcc-profile-make
+ profile_use = gcc-profile-use
+ ifeq ($(KERNEL),Darwin)
+ EXTRAPROFILEFLAGS = -fvisibility=hidden
+ endif
+endif
+
+### Sometimes gcc is really clang
+ifeq ($(COMP),gcc)
+ gccversion := $(shell $(CXX) --version 2>/dev/null)
+ gccisclang := $(findstring clang,$(gccversion))
+ ifneq ($(gccisclang),)
+ profile_make = clang-profile-make
+ profile_use = clang-profile-use
+ endif
+endif
+
+### On mingw use Windows threads, otherwise POSIX
+ifneq ($(comp),mingw)
+ CXXFLAGS += -DUSE_PTHREADS
+#On Android Bionic's C library comes with its own pthread implementation bundled in
+ ifneq ($(OS),Android)
+#Haiku has pthreads in its libroot, so only link it in on other platforms
+ ifneq ($(KERNEL),Haiku)
+ ifneq ($(COMP),ndk)
+ LDFLAGS += -lpthread
+ endif
+ endif
+ endif
+endif
+
+### 3.2.1 Debugging
+ifeq ($(debug),no)
+ CXXFLAGS += -DNDEBUG
+else
+ CXXFLAGS += -g
+endif
+
+### 3.2.2 Debugging with undefined behavior sanitizers
+ifneq ($(sanitize),none)
+ CXXFLAGS += -g3 $(addprefix -fsanitize=,$(sanitize))
+ LDFLAGS += $(addprefix -fsanitize=,$(sanitize))
+endif
+
+### 3.3 Optimization
+ifeq ($(optimize),yes)
+
+ CXXFLAGS += -O3 -funroll-loops
+
+ ifeq ($(comp),gcc)
+ ifeq ($(OS), Android)
+ CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
+ endif
+ endif
+
+ ifeq ($(KERNEL),Darwin)
+ ifeq ($(comp),$(filter $(comp),clang icx))
+ CXXFLAGS += -mdynamic-no-pic
+ endif
+
+ ifeq ($(comp),gcc)
+ ifneq ($(arch),arm64)
+ CXXFLAGS += -mdynamic-no-pic
+ endif
+ endif
+ endif
+
+ ifeq ($(comp),clang)
+ clangmajorversion := $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
+ ifeq ($(shell expr $(clangmajorversion) \< 16),1)
+ CXXFLAGS += -fexperimental-new-pass-manager
+ endif
+ endif
+endif
+
+### 3.4 Bits
+ifeq ($(bits),64)
+ CXXFLAGS += -DIS_64BIT
+endif
+
+### 3.5 prefetch and popcount
+ifeq ($(prefetch),yes)
+ ifeq ($(sse),yes)
+ CXXFLAGS += -msse
+ endif
+else
+ CXXFLAGS += -DNO_PREFETCH
+endif
+
+ifeq ($(popcnt),yes)
+ ifeq ($(arch),$(filter $(arch),ppc64 ppc64-altivec ppc64-vsx armv7 armv8 arm64))
+ CXXFLAGS += -DUSE_POPCNT
+ else
+ CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
+ endif
+endif
+
+### 3.6 SIMD architectures
+ifeq ($(avx2),yes)
+ CXXFLAGS += -DUSE_AVX2
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mavx2 -mbmi
+ endif
+endif
+
+ifeq ($(avxvnni),yes)
+ CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mavxvnni
+ endif
+endif
+
+ifeq ($(avx512),yes)
+ CXXFLAGS += -DUSE_AVX512
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mavx512f -mavx512bw
+ endif
+endif
+
+ifeq ($(vnni256),yes)
+ CXXFLAGS += -DUSE_VNNI
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256
+ endif
+endif
+
+ifeq ($(vnni512),yes)
+ CXXFLAGS += -DUSE_VNNI
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=512
+ endif
+endif
+
+ifeq ($(sse41),yes)
+ CXXFLAGS += -DUSE_SSE41
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -msse4.1
+ endif
+endif
+
+ifeq ($(ssse3),yes)
+ CXXFLAGS += -DUSE_SSSE3
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mssse3
+ endif
+endif
+
+ifeq ($(sse2),yes)
+ CXXFLAGS += -DUSE_SSE2
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -msse2
+ endif
+endif
+
+ifeq ($(mmx),yes)
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mmmx
+ endif
+endif
+
+ifeq ($(altivec),yes)
+ CXXFLAGS += -maltivec
+ ifeq ($(COMP),gcc)
+ CXXFLAGS += -mabi=altivec
+ endif
+endif
+
+ifeq ($(vsx),yes)
+ CXXFLAGS += -mvsx
+ ifeq ($(COMP),gcc)
+ CXXFLAGS += -DNO_WARN_X86_INTRINSICS -DUSE_SSE2
+ endif
+endif
+
+ifeq ($(neon),yes)
+ CXXFLAGS += -DUSE_NEON=$(arm_version)
+ ifeq ($(KERNEL),Linux)
+ ifneq ($(COMP),ndk)
+ ifneq ($(arch),armv8)
+ CXXFLAGS += -mfpu=neon
+ endif
+ endif
+ endif
+endif
+
+ifeq ($(dotprod),yes)
+ CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD
+endif
+
+ifeq ($(lasx),yes)
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mlasx
+ endif
+endif
+
+ifeq ($(lsx),yes)
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mlsx
+ endif
+endif
+
+### 3.7 pext
+ifeq ($(pext),yes)
+ CXXFLAGS += -DUSE_PEXT
+ ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
+ CXXFLAGS += -mbmi2
+ endif
+endif
+
+### 3.8.1 Try to include git commit sha for versioning
+GIT_SHA := $(shell git rev-parse HEAD 2>/dev/null | cut -c 1-8)
+ifneq ($(GIT_SHA), )
+ CXXFLAGS += -DGIT_SHA=$(GIT_SHA)
+endif
+
+### 3.8.2 Try to include git commit date for versioning
+GIT_DATE := $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null)
+ifneq ($(GIT_DATE), )
+ CXXFLAGS += -DGIT_DATE=$(GIT_DATE)
+endif
+
+### 3.8.3 Try to include architecture
+ifneq ($(ARCH), )
+ CXXFLAGS += -DARCH=$(ARCH)
+endif
+
+### 3.9 Link Time Optimization
+### This is a mix of compile and link time options because the lto link phase
+### needs access to the optimization flags.
+ifeq ($(optimize),yes)
+ifeq ($(debug), no)
+ ifeq ($(comp),$(filter $(comp),clang icx))
+ CXXFLAGS += -flto=full
+ ifeq ($(comp),icx)
+ CXXFLAGS += -fwhole-program-vtables
+ endif
+ ifeq ($(target_windows),yes)
+ CXXFLAGS += -fuse-ld=lld
+ endif
+ LDFLAGS += $(CXXFLAGS)
+
+#GCC and CLANG use different methods for parallelizing LTO and CLANG pretends to be
+#GCC on some systems.
+ else ifeq ($(comp),gcc)
+ ifeq ($(gccisclang),)
+ CXXFLAGS += -flto -flto-partition=one
+ LDFLAGS += $(CXXFLAGS) -flto=jobserver
+ else
+ CXXFLAGS += -flto=full
+ LDFLAGS += $(CXXFLAGS)
+ endif
+
+#To use LTO and static linking on Windows,
+#the tool chain requires gcc version 10.1 or later.
+ else ifeq ($(comp),mingw)
+ CXXFLAGS += -flto -flto-partition=one
+ LDFLAGS += $(CXXFLAGS) -save-temps
+ endif
+endif
+endif
+
+### 3.10 Android 5 can only run position independent executables. Note that this
+### breaks Android 4.0 and earlier.
+ifeq ($(OS), Android)
+ CXXFLAGS += -fPIE
+ LDFLAGS += -fPIE -pie
+endif
+
+### ==========================================================================
+### Section 4. Public Targets
+### ==========================================================================
+
+help:
+ @echo "" && \
+ echo "To compile cppchess_engine, type: " && \
+ echo "" && \
+ echo "make -j target [ARCH=arch] [COMP=compiler] [COMPCXX=cxx]" && \
+ echo "" && \
+ echo "Supported targets:" && \
+ echo "" && \
+ echo "help > Display architecture details" && \
+ echo "profile-build > standard build with profile-guided optimization" && \
+ echo "build > skip profile-guided optimization" && \
+ echo "net > Download the default nnue nets" && \
+ echo "strip > Strip executable" && \
+ echo "install > Install executable" && \
+ echo "clean > Clean up" && \
+ echo "" && \
+ echo "Supported archs:" && \
+ echo "" && \
+ echo "native > select the best architecture for the host processor (default)" && \
+ echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
+ echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \
+ echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
+ echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
+ echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
+ echo "x86-64-avx2 > x86 64-bit with avx2 support" && \
+ echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" && \
+ echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt" && \
+ echo "x86-64-ssse3 > x86 64-bit with ssse3 support" && \
+ echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support" && \
+ echo "x86-64 > x86 64-bit generic (with sse2 support)" && \
+ echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" && \
+ echo "x86-32-sse2 > x86 32-bit with sse2 support" && \
+ echo "x86-32 > x86 32-bit generic (with mmx compile support)" && \
+ echo "ppc-64 > PPC 64-bit" && \
+ echo "ppc-64-altivec > PPC 64-bit with altivec support" && \
+ echo "ppc-64-vsx > PPC 64-bit with vsx support" && \
+ echo "ppc-32 > PPC 32-bit" && \
+ echo "armv7 > ARMv7 32-bit" && \
+ echo "armv7-neon > ARMv7 32-bit with popcnt and neon" && \
+ echo "armv8 > ARMv8 64-bit with popcnt and neon" && \
+ echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" && \
+ echo "e2k > Elbrus 2000" && \
+ echo "apple-silicon > Apple silicon ARM64" && \
+ echo "general-64 > unspecified 64-bit" && \
+ echo "general-32 > unspecified 32-bit" && \
+ echo "riscv64 > RISC-V 64-bit" && \
+ echo "loongarch64 > LoongArch 64-bit" && \
+ echo "loongarch64-lsx > LoongArch 64-bit with SIMD eXtension" && \
+ echo "loongarch64-lasx > LoongArch 64-bit with Advanced SIMD eXtension" && \
+ echo "" && \
+ echo "Supported compilers:" && \
+ echo "" && \
+ echo "gcc > GNU compiler (default)" && \
+ echo "mingw > GNU compiler with MinGW under Windows" && \
+ echo "clang > LLVM Clang compiler" && \
+ echo "icx > Intel oneAPI DPC++/C++ Compiler" && \
+ echo "ndk > Google NDK to cross-compile for Android" && \
+ echo "" && \
+ echo "Simple examples. If you don't know what to do, you likely want to run one of: " && \
+ echo "" && \
+ echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems " && \
+ echo "make -j profile-build ARCH=x86-64-sse41-popcnt # A more portable compile for 64-bit systems " && \
+ echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems " && \
+ echo "" && \
+ echo "Advanced examples, for experienced users: " && \
+ echo "" && \
+ echo "make -j profile-build ARCH=x86-64-avxvnni" && \
+ echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc COMPCXX=g++-12.0" && \
+ echo "make -j build ARCH=x86-64-ssse3 COMP=clang" && \
+ echo ""
+ifneq ($(SUPPORTED_ARCH), true)
+ @echo "Specify a supported architecture with the ARCH option for more details"
+ @echo ""
+endif
+
+
+.PHONY: help analyze build profile-build strip install clean net \
+ objclean profileclean config-sanity \
+ icx-profile-use icx-profile-make \
+ gcc-profile-use gcc-profile-make \
+ clang-profile-use clang-profile-make FORCE \
+ format analyze
+
+analyze: net config-sanity objclean
+ $(MAKE) -k ARCH=$(ARCH) COMP=$(COMP) $(OBJS)
+
+build: net config-sanity
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
+
+profile-build: net config-sanity objclean profileclean
+ @echo ""
+ @echo "Step 1/4. Building instrumented executable ..."
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
+ @echo ""
+ @echo "Step 2/4. Running benchmark for pgo-build ..."
+ $(PGOBENCH) > PGOBENCH.out 2>&1
+ tail -n 4 PGOBENCH.out
+ @echo ""
+ @echo "Step 3/4. Building optimized executable ..."
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
+ @echo ""
+ @echo "Step 4/4. Deleting profile data ..."
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) profileclean
+
+strip:
+ $(STRIP) $(EXE)
+
+install:
+ -mkdir -p -m 755 $(BINDIR)
+ -cp $(EXE) $(BINDIR)
+ $(STRIP) $(BINDIR)/$(EXE)
+
+#clean all
+clean: objclean profileclean
+ @rm -f .depend *~ core
+
+#clean binaries and objects
+objclean:
+ @rm -f cppchess_engine cppchess_engine.exe *.o ./nnue/features/*.o ./nnue/*.o
+
+# clean auxiliary profiling files
+profileclean:
+ @rm -rf profdir
+ @rm -f bench.txt *.gcda *.gcno ./nnue/*.gcda ./nnue/features/*.gcda *.s PGOBENCH.out
+ @rm -f cppchess_engine.profdata *.profraw
+ @rm -f cppchess_engine.*args*
+ @rm -f cppchess_engine.*lt*
+ @rm -f cppchess_engine.res
+ @rm -f ./-lstdc++.res
+
+# evaluation network (nnue)
+net:
+ @$(SHELL) ../scripts/net.sh
+
+format:
+ $(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
+
+# default target
+default:
+ help
+
+### ==========================================================================
+### Section 5. Private Targets
+### ==========================================================================
+
+all: $(EXE) .depend
+
+config-sanity: net
+ @echo ""
+ @echo "Config:" && \
+ echo "debug: '$(debug)'" && \
+ echo "sanitize: '$(sanitize)'" && \
+ echo "optimize: '$(optimize)'" && \
+ echo "arch: '$(arch)'" && \
+ echo "bits: '$(bits)'" && \
+ echo "kernel: '$(KERNEL)'" && \
+ echo "os: '$(OS)'" && \
+ echo "prefetch: '$(prefetch)'" && \
+ echo "popcnt: '$(popcnt)'" && \
+ echo "pext: '$(pext)'" && \
+ echo "sse: '$(sse)'" && \
+ echo "mmx: '$(mmx)'" && \
+ echo "sse2: '$(sse2)'" && \
+ echo "ssse3: '$(ssse3)'" && \
+ echo "sse41: '$(sse41)'" && \
+ echo "avx2: '$(avx2)'" && \
+ echo "avxvnni: '$(avxvnni)'" && \
+ echo "avx512: '$(avx512)'" && \
+ echo "vnni256: '$(vnni256)'" && \
+ echo "vnni512: '$(vnni512)'" && \
+ echo "altivec: '$(altivec)'" && \
+ echo "vsx: '$(vsx)'" && \
+ echo "neon: '$(neon)'" && \
+ echo "dotprod: '$(dotprod)'" && \
+ echo "arm_version: '$(arm_version)'" && \
+ echo "lsx: '$(lsx)'" && \
+ echo "lasx: '$(lasx)'" && \
+ echo "target_windows: '$(target_windows)'" && \
+ echo "" && \
+ echo "Flags:" && \
+ echo "CXX: $(CXX)" && \
+ echo "CXXFLAGS: $(CXXFLAGS)" && \
+ echo "LDFLAGS: $(LDFLAGS)" && \
+ echo "" && \
+ echo "Testing config sanity. If this fails, try 'make help' ..." && \
+ echo "" && \
+ (test "$(debug)" = "yes" || test "$(debug)" = "no") && \
+ (test "$(optimize)" = "yes" || test "$(optimize)" = "no") && \
+ (test "$(SUPPORTED_ARCH)" = "true") && \
+ (test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
+ test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
+ test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || \
+ test "$(arch)" = "riscv64" || test "$(arch)" = "loongarch64") && \
+ (test "$(bits)" = "32" || test "$(bits)" = "64") && \
+ (test "$(prefetch)" = "yes" || test "$(prefetch)" = "no") && \
+ (test "$(popcnt)" = "yes" || test "$(popcnt)" = "no") && \
+ (test "$(pext)" = "yes" || test "$(pext)" = "no") && \
+ (test "$(sse)" = "yes" || test "$(sse)" = "no") && \
+ (test "$(mmx)" = "yes" || test "$(mmx)" = "no") && \
+ (test "$(sse2)" = "yes" || test "$(sse2)" = "no") && \
+ (test "$(ssse3)" = "yes" || test "$(ssse3)" = "no") && \
+ (test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \
+ (test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \
+ (test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \
+ (test "$(vnni256)" = "yes" || test "$(vnni256)" = "no") && \
+ (test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \
+ (test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \
+ (test "$(vsx)" = "yes" || test "$(vsx)" = "no") && \
+ (test "$(neon)" = "yes" || test "$(neon)" = "no") && \
+ (test "$(lsx)" = "yes" || test "$(lsx)" = "no") && \
+ (test "$(lasx)" = "yes" || test "$(lasx)" = "no") && \
+ (test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || \
+ test "$(comp)" = "clang" || test "$(comp)" = "armv7a-linux-androideabi16-clang" || \
+ test "$(comp)" = "aarch64-linux-android21-clang")
+
+$(EXE): $(OBJS)
+ +$(CXX) -o $@ $(OBJS) $(LDFLAGS)
+
+# Force recompilation to ensure version info is up-to-date
+misc.o: FORCE
+FORCE:
+
+clang-profile-make:
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+ EXTRACXXFLAGS='-fprofile-generate ' \
+ EXTRALDFLAGS=' -fprofile-generate' \
+ all
+
+clang-profile-use:
+ $(XCRUN) $(LLVM_PROFDATA) merge -output=cppchess_engine.profdata *.profraw
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+ EXTRACXXFLAGS='-fprofile-use=cppchess_engine.profdata' \
+ EXTRALDFLAGS='-fprofile-use ' \
+ all
+
+gcc-profile-make:
+ @mkdir -p profdir
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+ EXTRACXXFLAGS='-fprofile-generate=profdir' \
+ EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \
+ EXTRALDFLAGS='-lgcov' \
+ all
+
+gcc-profile-use:
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+ EXTRACXXFLAGS='-fprofile-use=profdir -fno-peel-loops -fno-tracer' \
+ EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \
+ EXTRALDFLAGS='-lgcov' \
+ all
+
+icx-profile-make:
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+ EXTRACXXFLAGS='-fprofile-instr-generate ' \
+ EXTRALDFLAGS=' -fprofile-instr-generate' \
+ all
+
+icx-profile-use:
+ $(XCRUN) llvm-profdata merge -output=cppchess_engine.profdata *.profraw
+ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
+ EXTRACXXFLAGS='-fprofile-instr-use=cppchess_engine.profdata' \
+ EXTRALDFLAGS='-fprofile-use ' \
+ all
+
+.depend: $(SRCS)
+ -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
+
+ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean config-sanity))
+-include .depend
+endif
diff --git a/README.md b/src/README.md
similarity index 88%
rename from README.md
rename to src/README.md
index 1841726..d1bf29e 100644
--- a/README.md
+++ b/src/README.md
@@ -1,4 +1,4 @@
-# cppchess_engine
+#cppchess_engine
A minimal UCI-compilant (no time control now) chess engine
diff --git a/src/bitboard.h b/src/bitboard.h
new file mode 100644
index 0000000..d0de72a
--- /dev/null
+++ b/src/bitboard.h
@@ -0,0 +1,141 @@
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef BITBOARD_H_INCLUDED
+#define BITBOARD_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "types.h"
+
+namespace Stockfish {
+
+// Counts the number of non-zero bits in a bitboard.
+inline int popcount(Bitboard b) {
+
+#ifndef USE_POPCNT
+
+ b = b - ((b >> 1) & 0x5555555555555555ULL);
+ b = (b & 0x3333333333333333ULL) + ((b >> 2) & 0x3333333333333333ULL);
+ b = (b + (b >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ return (b * 0x0101010101010101ULL) >> 56;
+
+#elif defined(_MSC_VER)
+
+ return int(_mm_popcnt_u64(b));
+
+#else // Assumed gcc or compatible compiler
+
+ return __builtin_popcountll(b);
+
+#endif
+}
+
+// Returns the least significant bit in a non-zero bitboard.
+inline Square lsb(Bitboard b) {
+ assert(b);
+
+#if defined(__GNUC__) // GCC, Clang, ICX
+
+ return Square(__builtin_ctzll(b));
+
+#elif defined(_MSC_VER)
+ #ifdef _WIN64 // MSVC, WIN64
+
+ unsigned long idx;
+ _BitScanForward64(&idx, b);
+ return Square(idx);
+
+ #else // MSVC, WIN32
+ 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);
+ }
+ #endif
+#else // Compiler is neither GCC nor MSVC compatible
+ #error "Compiler not supported."
+#endif
+}
+
+// Returns the most significant bit in a non-zero bitboard.
+inline Square msb(Bitboard b) {
+ assert(b);
+
+#if defined(__GNUC__) // GCC, Clang, ICX
+
+ return Square(63 ^ __builtin_clzll(b));
+
+#elif defined(_MSC_VER)
+ #ifdef _WIN64 // MSVC, WIN64
+
+ unsigned long idx;
+ _BitScanReverse64(&idx, b);
+ return Square(idx);
+
+ #else // MSVC, WIN32
+
+ 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
+}
+
+// Returns the bitboard of the least significant
+// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)).
+inline Bitboard least_significant_square_bb(Bitboard b) {
+ assert(b);
+ return b & -b;
+}
+
+// Finds and clears the least significant bit in a non-zero bitboard.
+inline Square pop_lsb(Bitboard& b) {
+ assert(b);
+ const Square s = lsb(b);
+ b &= b - 1;
+ return s;
+}
+
+} // namespace Stockfish
+
+#endif // #ifndef BITBOARD_H_INCLUDED
diff --git a/chess.hpp b/src/chess.hpp
similarity index 60%
rename from chess.hpp
rename to src/chess.hpp
index c2c7698..98ab643 100644
--- a/chess.hpp
+++ b/src/chess.hpp
@@ -25,12 +25,15 @@ THIS FILE IS AUTO GENERATED DO NOT CHANGE MANUALLY.
Source: https://github.com/Disservin/chess-library
-VERSION: 0.8.13
+VERSION: 0.8.2
*/
#ifndef CHESS_HPP
#define CHESS_HPP
-
+#ifndef NDEBUG
+ #define NDEBUG
+ #define CHESS_NO_EXCEPTIONS
+#endif
#include
#include
@@ -38,12 +41,12 @@ VERSION: 0.8.13
#include
#ifdef CHESS_USE_PEXT
-# include
+ #include
#endif
#if __cpp_lib_bitops >= 201907L
-# include
+ #include
#endif
#include
#include
@@ -52,8 +55,8 @@ VERSION: 0.8.13
#include
#if defined(_MSC_VER)
-# include
-# include
+ #include
+ #include
#endif
@@ -66,15 +69,26 @@ namespace chess {
class Color {
public:
- enum class underlying : std::int8_t { WHITE = 0, BLACK = 1, NONE = -1 };
+ enum class underlying : std::int8_t {
+ WHITE = 0,
+ BLACK = 1,
+ NONE = -1
+ };
- constexpr Color() : color(underlying::NONE) {}
- constexpr Color(underlying c) : color(c) { assert(isValid(static_cast(c))); }
- constexpr Color(int c) : Color(static_cast(c)) { assert(isValid(c)); }
- constexpr Color(std::string_view str)
- : color(str == "w" ? underlying::WHITE
- : str == "b" ? underlying::BLACK
- : underlying::NONE) {}
+ constexpr Color() :
+ color(underlying::NONE) {}
+ constexpr Color(underlying c) :
+ color(c) {
+ assert(isValid(static_cast(c)));
+ }
+ constexpr Color(int c) :
+ Color(static_cast(c)) {
+ assert(isValid(c));
+ }
+ constexpr Color(std::string_view str) :
+ color(str == "w" ? underlying::WHITE
+ : str == "b" ? underlying::BLACK
+ : underlying::NONE) {}
/**
* @brief Gets the long string representation of the color
@@ -82,13 +96,14 @@ class Color {
* "None" for NONE
*/
[[nodiscard]] std::string longStr() const {
- switch (color) {
- case underlying::WHITE:
- return "White";
- case underlying::BLACK:
- return "Black";
- default:
- return "None";
+ switch (color)
+ {
+ case underlying::WHITE :
+ return "White";
+ case underlying::BLACK :
+ return "Black";
+ default :
+ return "None";
}
}
@@ -108,8 +123,8 @@ class Color {
[[nodiscard]] constexpr underlying internal() const noexcept { return color; }
- friend std::ostream& operator<<(std::ostream& os, const Color& color) {
- return os << static_cast(color);
+ friend std::ostream& operator<<(std::ostream& os, const Color& _color) {
+ return os << static_cast(_color);
}
static constexpr underlying WHITE = underlying::WHITE;
@@ -123,9 +138,9 @@ class Color {
};
constexpr Color::underlying operator~(Color::underlying color) {
- return color == Color::underlying::WHITE ? Color::underlying::BLACK
- : color == Color::underlying::BLACK ? Color::underlying::WHITE
- : Color::underlying::NONE;
+ return color == Color::underlying::WHITE ? Color::underlying::BLACK
+ : color == Color::underlying::BLACK ? Color::underlying::WHITE
+ : Color::underlying::NONE;
}
} // namespace chess
@@ -136,12 +151,14 @@ namespace chess {
namespace utils {
// Split a string by a delimiter
-[[nodiscard]] inline std::vector splitString(std::string_view string, const char &delimiter) {
+[[nodiscard]] inline std::vector splitString(std::string_view string,
+ const char& delimiter) {
std::vector result;
- size_t start = 0;
- size_t end = string.find(delimiter);
+ size_t start = 0;
+ size_t end = string.find(delimiter);
- while (end != std::string_view::npos) {
+ while (end != std::string_view::npos)
+ {
result.push_back(string.substr(start, end - start));
start = end + 1;
end = string.find(delimiter, start);
@@ -161,7 +178,7 @@ constexpr char tolower(char c) { return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a')
namespace chess {
-#define CHESS_DECLARE_RANK(N) \
+#define CHESS_DECLARE_RANK(N) \
static constexpr auto SQ_A##N = underlying::SQ_A##N; \
static constexpr auto SQ_B##N = underlying::SQ_B##N; \
static constexpr auto SQ_C##N = underlying::SQ_C##N; \
@@ -173,13 +190,29 @@ namespace chess {
class File {
public:
- enum class underlying : std::uint8_t { FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, NO_FILE };
+ enum class underlying : std::uint8_t {
+ FILE_A,
+ FILE_B,
+ FILE_C,
+ FILE_D,
+ FILE_E,
+ FILE_F,
+ FILE_G,
+ FILE_H,
+ NO_FILE
+ };
- constexpr File() : file(underlying::NO_FILE) {}
- constexpr File(underlying file) : file(file) {}
- constexpr File(int file) : file(static_cast(file)) {}
- constexpr File(std::string_view sw)
- : file(static_cast(static_cast(utils::tolower(static_cast(sw[0]))) - 'a')) {}
+ constexpr File() :
+ file(underlying::NO_FILE) {}
+ constexpr File(underlying file) :
+ file(file) {}
+ constexpr File(int file) :
+ file(static_cast(file)) {}
+ constexpr File(std::string_view sw) :
+ file(sw.empty()
+ ? underlying::NO_FILE
+ : static_cast(
+ static_cast(utils::tolower(static_cast(sw[0]))) - 'a')) {}
[[nodiscard]] constexpr underlying internal() const noexcept { return file; }
@@ -211,7 +244,9 @@ class File {
constexpr operator int() const noexcept { return static_cast(file); }
- explicit operator std::string() const { return std::string(1, static_cast(static_cast(file) + 'a')); }
+ explicit operator std::string() const {
+ return std::string(1, static_cast(static_cast(file) + 'a'));
+ }
static constexpr underlying FILE_A = underlying::FILE_A;
static constexpr underlying FILE_B = underlying::FILE_B;
@@ -229,13 +264,27 @@ class File {
class Rank {
public:
- enum class underlying { RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, NO_RANK };
+ enum class underlying {
+ RANK_1,
+ RANK_2,
+ RANK_3,
+ RANK_4,
+ RANK_5,
+ RANK_6,
+ RANK_7,
+ RANK_8,
+ NO_RANK
+ };
- constexpr Rank() : rank_(underlying::NO_RANK) {}
- constexpr Rank(underlying rank) : rank_(rank) {}
- constexpr Rank(int rank) : rank_(static_cast(rank)) {}
- constexpr Rank(std::string_view sw)
- : rank_(static_cast(static_cast(utils::tolower(static_cast(sw[0]))) - '1')) {}
+ constexpr Rank() :
+ rank_(underlying::NO_RANK) {}
+ constexpr Rank(underlying rank) :
+ rank_(rank) {}
+ constexpr Rank(int rank) :
+ rank_(static_cast(rank)) {}
+ constexpr Rank(std::string_view sw) :
+ rank_(static_cast(
+ static_cast(utils::tolower(static_cast(sw[0]))) - '1')) {}
[[nodiscard]] constexpr underlying internal() const noexcept { return rank_; }
@@ -257,11 +306,15 @@ class Rank {
return *this;
}
- operator std::string() const { return std::string(1, static_cast(static_cast(rank_) + '1')); }
+ operator std::string() const {
+ return std::string(1, static_cast(static_cast(rank_) + '1'));
+ }
constexpr operator int() const noexcept { return static_cast(rank_); }
- [[nodiscard]] constexpr std::uint64_t bb() const noexcept { return 0xffULL << (8 * static_cast(rank_)); }
+ [[nodiscard]] constexpr std::uint64_t bb() const noexcept {
+ return 0xffULL << (8 * static_cast(rank_));
+ }
[[nodiscard]] static constexpr bool back_rank(Rank r, Color color) noexcept {
return r == Rank(static_cast(color) * 7);
@@ -319,13 +372,21 @@ class Square {
#endif
- constexpr Square() : sq(underlying::NO_SQ) {}
-
- constexpr Square(int sq) : sq(static_cast(sq)) { assert(sq <= 64 && sq >= 0); }
- constexpr Square(File file, Rank rank) : sq(static_cast(file + rank * 8)) {}
- constexpr Square(Rank rank, File file) : sq(static_cast(file + rank * 8)) {}
- constexpr Square(underlying sq) : sq(sq) {}
- constexpr Square(std::string_view str) : sq(static_cast((str[0] - 'a') + (str[1] - '1') * 8)) {
+ constexpr Square() :
+ sq(underlying::NO_SQ) {}
+
+ constexpr Square(int sq) :
+ sq(static_cast(sq)) {
+ assert(sq <= 64 && sq >= 0);
+ }
+ constexpr Square(File file, Rank rank) :
+ sq(static_cast(file + rank * 8)) {}
+ constexpr Square(Rank rank, File file) :
+ sq(static_cast(file + rank * 8)) {}
+ constexpr Square(underlying sq) :
+ sq(sq) {}
+ constexpr Square(std::string_view str) :
+ sq(static_cast((str[0] - 'a') + (str[1] - '1') * 8)) {
assert(str.size() >= 2);
}
@@ -402,8 +463,7 @@ class Square {
* @brief Check if the square is light.
* @return
*/
- [[nodiscard]] constexpr bool is_light() const noexcept { return (file() + rank()) & 1;
- }
+ [[nodiscard]] constexpr bool is_light() const noexcept { return (file() + rank()) & 1; }
/**
* @brief Check if the square is dark.
@@ -412,10 +472,12 @@ class Square {
[[nodiscard]] constexpr bool is_dark() const noexcept { return !is_light(); }
/**
- * @brief Check if the square is vali.d
+ * @brief Check if the square is valid
* @return
*/
- [[nodiscard]] constexpr bool is_valid() const noexcept { return static_cast(sq) < 64; }
+ [[nodiscard]] constexpr bool is_valid() const noexcept {
+ return static_cast(sq) < 64;
+ }
/**
* @brief Check if the square is valid.
@@ -508,7 +570,8 @@ class Square {
* @param c
* @return
*/
- [[nodiscard]] static constexpr Square castling_king_square(bool is_king_side, Color c) noexcept {
+ [[nodiscard]] static constexpr Square castling_king_square(bool is_king_side,
+ Color c) noexcept {
return Square(is_king_side ? Square::SQ_G1 : Square::SQ_C1).relative_square(c);
}
@@ -518,7 +581,8 @@ class Square {
* @param c
* @return
*/
- [[nodiscard]] static constexpr Square castling_rook_square(bool is_king_side, Color c) noexcept {
+ [[nodiscard]] static constexpr Square castling_rook_square(bool is_king_side,
+ Color c) noexcept {
return Square(is_king_side ? Square::SQ_F1 : Square::SQ_D1).relative_square(c);
}
@@ -555,7 +619,8 @@ enum class Direction : std::int8_t {
};
[[nodiscard]] constexpr Direction make_direction(Direction dir, Color c) noexcept {
- if (c == Color::BLACK) return static_cast(-static_cast(dir));
+ if (c == Color::BLACK)
+ return static_cast(-static_cast(dir));
return dir;
}
@@ -571,13 +636,17 @@ namespace chess {
class Bitboard {
public:
- constexpr Bitboard() : bits(0) {}
- constexpr Bitboard(std::uint64_t bits) : bits(bits) {}
- constexpr Bitboard(File file) : bits(0) {
+ constexpr Bitboard() :
+ bits(0) {}
+ constexpr Bitboard(std::uint64_t bits) :
+ bits(bits) {}
+ constexpr Bitboard(File file) :
+ bits(0) {
assert(file != File::NO_FILE);
bits = 0x0101010101010101ULL << static_cast(file.internal());
}
- constexpr Bitboard(Rank rank) : bits(0) {
+ constexpr Bitboard(Rank rank) :
+ bits(0) {
assert(rank != Rank::NO_RANK);
bits = 0xFFULL << (8 * static_cast(rank.internal()));
}
@@ -586,11 +655,12 @@ class Bitboard {
explicit operator std::string() const {
std::bitset<64> b(bits);
- std::string str_bitset = b.to_string();
+ std::string str_bitset = b.to_string();
std::string str;
- for (int i = 0; i < 64; i += 8) {
+ for (int i = 0; i < 64; i += 8)
+ {
std::string x = str_bitset.substr(i, 8);
std::reverse(x.begin(), x.end());
str += x + '\n';
@@ -603,14 +673,24 @@ class Bitboard {
constexpr Bitboard operator&(std::uint64_t rhs) const noexcept { return Bitboard(bits & rhs); }
constexpr Bitboard operator|(std::uint64_t rhs) const noexcept { return Bitboard(bits | rhs); }
constexpr Bitboard operator^(std::uint64_t rhs) const noexcept { return Bitboard(bits ^ rhs); }
- constexpr Bitboard operator<<(std::uint64_t rhs) const noexcept { return Bitboard(bits << rhs); }
- constexpr Bitboard operator>>(std::uint64_t rhs) const noexcept { return Bitboard(bits >> rhs); }
+ constexpr Bitboard operator<<(std::uint64_t rhs) const noexcept {
+ return Bitboard(bits << rhs);
+ }
+ constexpr Bitboard operator>>(std::uint64_t rhs) const noexcept {
+ return Bitboard(bits >> rhs);
+ }
constexpr bool operator==(std::uint64_t rhs) const noexcept { return bits == rhs; }
constexpr bool operator!=(std::uint64_t rhs) const noexcept { return bits != rhs; }
- constexpr Bitboard operator&(const Bitboard& rhs) const noexcept { return Bitboard(bits & rhs.bits); }
- constexpr Bitboard operator|(const Bitboard& rhs) const noexcept { return Bitboard(bits | rhs.bits); }
- constexpr Bitboard operator^(const Bitboard& rhs) const noexcept { return Bitboard(bits ^ rhs.bits); }
+ constexpr Bitboard operator&(const Bitboard& rhs) const noexcept {
+ return Bitboard(bits & rhs.bits);
+ }
+ constexpr Bitboard operator|(const Bitboard& rhs) const noexcept {
+ return Bitboard(bits | rhs.bits);
+ }
+ constexpr Bitboard operator^(const Bitboard& rhs) const noexcept {
+ return Bitboard(bits ^ rhs.bits);
+ }
constexpr Bitboard operator~() const noexcept { return Bitboard(~bits); }
constexpr Bitboard& operator&=(const Bitboard& rhs) noexcept {
@@ -671,20 +751,20 @@ class Bitboard {
#if __cpp_lib_bitops >= 201907L
constexpr
#endif
- int lsb() const noexcept {
+ int lsb() const noexcept {
assert(bits != 0);
#if __cpp_lib_bitops >= 201907L
return std::countr_zero(bits);
#else
-# if defined(__GNUC__)
+ #if defined(__GNUC__)
return __builtin_ctzll(bits);
-# elif defined(_MSC_VER)
+ #elif defined(_MSC_VER)
unsigned long idx;
_BitScanForward64(&idx, bits);
return static_cast(idx);
-# else
-# error "Compiler not supported."
-# endif
+ #else
+ #error "Compiler not supported."
+ #endif
#endif
}
@@ -692,21 +772,21 @@ class Bitboard {
#if __cpp_lib_bitops >= 201907L
constexpr
#endif
- int msb() const noexcept {
+ int msb() const noexcept {
assert(bits != 0);
#if __cpp_lib_bitops >= 201907L
return std::countl_zero(bits) ^ 63;
#else
-# if defined(__GNUC__)
+ #if defined(__GNUC__)
return 63 ^ __builtin_clzll(bits);
-# elif defined(_MSC_VER)
+ #elif defined(_MSC_VER)
unsigned long idx;
_BitScanReverse64(&idx, bits);
return static_cast(idx);
-# else
-# error "Compiler not supported."
-# endif
+ #else
+ #error "Compiler not supported."
+ #endif
#endif
}
@@ -714,15 +794,15 @@ class Bitboard {
#if __cpp_lib_bitops >= 201907L
constexpr
#endif
- int count() const noexcept {
+ int count() const noexcept {
#if __cpp_lib_bitops >= 201907L
return std::popcount(bits);
#else
-# if defined(_MSC_VER) || defined(__INTEL_COMPILER)
+ #if defined(_MSC_VER) || defined(__INTEL_COMPILER)
return static_cast(_mm_popcnt_u64(bits));
-# else
+ #else
return __builtin_popcountll(bits);
-# endif
+ #endif
#endif
}
@@ -730,7 +810,7 @@ class Bitboard {
#if __cpp_lib_bitops >= 201907L
constexpr
#endif
- std::uint8_t pop() noexcept {
+ std::uint8_t pop() noexcept {
assert(bits != 0);
std::uint8_t index = lsb();
bits &= bits - 1;
@@ -759,7 +839,6 @@ class Board;
} // namespace chess
-
namespace chess {
class PieceType {
@@ -774,9 +853,12 @@ class PieceType {
NONE,
};
- constexpr PieceType() : pt(underlying::NONE) {}
- constexpr PieceType(underlying pt) : pt(pt) {}
- constexpr explicit PieceType(std::string_view type) : pt(underlying::NONE) {
+ constexpr PieceType() :
+ pt(underlying::NONE) {}
+ constexpr PieceType(underlying pt) :
+ pt(pt) {}
+ constexpr explicit PieceType(std::string_view type) :
+ pt(underlying::NONE) {
assert(type.size() > 0);
char c = type[0];
@@ -798,7 +880,8 @@ class PieceType {
}
explicit operator std::string() const {
- if (pt == underlying::NONE) return " ";
+ if (pt == underlying::NONE)
+ return " ";
constexpr static const char* pieceTypeStr[] = {"p", "n", "b", "r", "q", "k"};
return pieceTypeStr[static_cast(pt)];
}
@@ -845,17 +928,24 @@ class Piece {
NONE
};
- constexpr Piece() : piece(underlying::NONE) {}
- constexpr Piece(underlying piece) : piece(piece) {}
- constexpr Piece(PieceType type, Color color)
- : piece(color == Color::NONE ? Piece::NONE
- : type == PieceType::NONE ? Piece::NONE
- : static_cast(static_cast(color.internal()) * 6 + type)) {}
- constexpr Piece(Color color, PieceType type)
- : piece(color == Color::NONE ? Piece::NONE
- : type == PieceType::NONE ? Piece::NONE
- : static_cast(static_cast(color.internal()) * 6 + type)) {}
- constexpr Piece(std::string_view p) : piece(underlying::NONE) { piece = convertCharToUnderlying(p[0]); }
+ constexpr Piece() :
+ piece(underlying::NONE) {}
+ constexpr Piece(underlying piece) :
+ piece(piece) {}
+ constexpr Piece(PieceType type, Color color) :
+ piece(color == Color::NONE ? Piece::NONE
+ : type == PieceType::NONE
+ ? Piece::NONE
+ : static_cast(static_cast(color.internal()) * 6 + type)) {}
+ constexpr Piece(Color color, PieceType type) :
+ piece(color == Color::NONE ? Piece::NONE
+ : type == PieceType::NONE
+ ? Piece::NONE
+ : static_cast(static_cast(color.internal()) * 6 + type)) {}
+ constexpr Piece(std::string_view p) :
+ piece(underlying::NONE) {
+ piece = convertCharToUnderlying(p[0]);
+ }
constexpr bool operator<(const Piece& rhs) const noexcept { return piece < rhs.piece; }
constexpr bool operator>(const Piece& rhs) const noexcept { return piece > rhs.piece; }
@@ -871,21 +961,24 @@ class Piece {
explicit operator std::string() const {
constexpr static const char* pieceStr[] = {"P", "N", "B", "R", "Q", "K", //
"p", "n", "b", "r", "q", "k"};
- if (piece == NONE) return ".";
+ if (piece == NONE)
+ return ".";
return pieceStr[static_cast(piece)];
}
constexpr operator int() const noexcept { return static_cast(piece); }
[[nodiscard]] constexpr PieceType type() const noexcept {
- if (piece == NONE) return PieceType::NONE;
+ if (piece == NONE)
+ return PieceType::NONE;
// return static_cast(int(piece) % 6);
- return static_cast(static_cast(piece) > 5 ? static_cast(piece) - 6
- : static_cast(piece));
+ return static_cast(
+ static_cast(piece) > 5 ? static_cast(piece) - 6 : static_cast(piece));
}
[[nodiscard]] constexpr Color color() const noexcept {
- if (piece == NONE) return Color::NONE;
+ if (piece == NONE)
+ return Color::NONE;
return static_cast(static_cast(piece) / 6);
}
@@ -909,33 +1002,34 @@ class Piece {
underlying piece;
[[nodiscard]] constexpr static underlying convertCharToUnderlying(char c) {
- switch (c) {
- case 'P':
- return WHITEPAWN;
- case 'N':
- return WHITEKNIGHT;
- case 'B':
- return WHITEBISHOP;
- case 'R':
- return WHITEROOK;
- case 'Q':
- return WHITEQUEEN;
- case 'K':
- return WHITEKING;
- case 'p':
- return BLACKPAWN;
- case 'n':
- return BLACKKNIGHT;
- case 'b':
- return BLACKBISHOP;
- case 'r':
- return BLACKROOK;
- case 'q':
- return BLACKQUEEN;
- case 'k':
- return BLACKKING;
- default:
- return NONE;
+ switch (c)
+ {
+ case 'P' :
+ return WHITEPAWN;
+ case 'N' :
+ return WHITEKNIGHT;
+ case 'B' :
+ return WHITEBISHOP;
+ case 'R' :
+ return WHITEROOK;
+ case 'Q' :
+ return WHITEQUEEN;
+ case 'K' :
+ return WHITEKING;
+ case 'p' :
+ return BLACKPAWN;
+ case 'n' :
+ return BLACKKNIGHT;
+ case 'b' :
+ return BLACKBISHOP;
+ case 'r' :
+ return BLACKROOK;
+ case 'q' :
+ return BLACKQUEEN;
+ case 'k' :
+ return BLACKKING;
+ default :
+ return NONE;
}
}
};
@@ -947,27 +1041,31 @@ class attacks {
#ifdef CHESS_USE_PEXT
struct Magic {
- U64 mask;
- Bitboard *attacks;
- U64 operator()(Bitboard b) const noexcept { return _pext_u64(b.getBits(), mask); }
+ U64 mask;
+ Bitboard* attacks;
+ U64 operator()(Bitboard b) const noexcept { return _pext_u64(b.getBits(), mask); }
};
#else
struct Magic {
- U64 mask;
- U64 magic;
- Bitboard *attacks;
- U64 shift;
- U64 operator()(Bitboard b) const noexcept { return (((b & mask)).getBits() * magic) >> shift; }
+ U64 mask;
+ U64 magic;
+ Bitboard* attacks;
+ U64 shift;
+ U64 operator()(Bitboard b) const noexcept {
+ return (((b & mask)).getBits() * magic) >> shift;
+ }
};
#endif
// Slow function to calculate bishop and rook attacks
- template
+ template
[[nodiscard]] static Bitboard sliderAttacks(Square sq, Bitboard occupied) noexcept;
// Initializes the magic bitboard tables for sliding pieces
- static void initSliders(Square sq, Magic table[], U64 magic,
- const std::function &attacks);
+ static void initSliders(Square sq,
+ Magic table[],
+ U64 magic,
+ const std::function& attacks);
// clang-format off
// pre-calculated lookup table for pawn attacks
@@ -1014,71 +1112,77 @@ class attacks {
// pre-calculated lookup table for knight attacks
static constexpr Bitboard KnightAttacks[64] = {
- 0x0000000000020400, 0x0000000000050800, 0x00000000000A1100, 0x0000000000142200, 0x0000000000284400,
- 0x0000000000508800, 0x0000000000A01000, 0x0000000000402000, 0x0000000002040004, 0x0000000005080008,
- 0x000000000A110011, 0x0000000014220022, 0x0000000028440044, 0x0000000050880088, 0x00000000A0100010,
- 0x0000000040200020, 0x0000000204000402, 0x0000000508000805, 0x0000000A1100110A, 0x0000001422002214,
- 0x0000002844004428, 0x0000005088008850, 0x000000A0100010A0, 0x0000004020002040, 0x0000020400040200,
- 0x0000050800080500, 0x00000A1100110A00, 0x0000142200221400, 0x0000284400442800, 0x0000508800885000,
- 0x0000A0100010A000, 0x0000402000204000, 0x0002040004020000, 0x0005080008050000, 0x000A1100110A0000,
- 0x0014220022140000, 0x0028440044280000, 0x0050880088500000, 0x00A0100010A00000, 0x0040200020400000,
- 0x0204000402000000, 0x0508000805000000, 0x0A1100110A000000, 0x1422002214000000, 0x2844004428000000,
- 0x5088008850000000, 0xA0100010A0000000, 0x4020002040000000, 0x0400040200000000, 0x0800080500000000,
- 0x1100110A00000000, 0x2200221400000000, 0x4400442800000000, 0x8800885000000000, 0x100010A000000000,
- 0x2000204000000000, 0x0004020000000000, 0x0008050000000000, 0x00110A0000000000, 0x0022140000000000,
- 0x0044280000000000, 0x0088500000000000, 0x0010A00000000000, 0x0020400000000000};
+ 0x0000000000020400, 0x0000000000050800, 0x00000000000A1100, 0x0000000000142200,
+ 0x0000000000284400, 0x0000000000508800, 0x0000000000A01000, 0x0000000000402000,
+ 0x0000000002040004, 0x0000000005080008, 0x000000000A110011, 0x0000000014220022,
+ 0x0000000028440044, 0x0000000050880088, 0x00000000A0100010, 0x0000000040200020,
+ 0x0000000204000402, 0x0000000508000805, 0x0000000A1100110A, 0x0000001422002214,
+ 0x0000002844004428, 0x0000005088008850, 0x000000A0100010A0, 0x0000004020002040,
+ 0x0000020400040200, 0x0000050800080500, 0x00000A1100110A00, 0x0000142200221400,
+ 0x0000284400442800, 0x0000508800885000, 0x0000A0100010A000, 0x0000402000204000,
+ 0x0002040004020000, 0x0005080008050000, 0x000A1100110A0000, 0x0014220022140000,
+ 0x0028440044280000, 0x0050880088500000, 0x00A0100010A00000, 0x0040200020400000,
+ 0x0204000402000000, 0x0508000805000000, 0x0A1100110A000000, 0x1422002214000000,
+ 0x2844004428000000, 0x5088008850000000, 0xA0100010A0000000, 0x4020002040000000,
+ 0x0400040200000000, 0x0800080500000000, 0x1100110A00000000, 0x2200221400000000,
+ 0x4400442800000000, 0x8800885000000000, 0x100010A000000000, 0x2000204000000000,
+ 0x0004020000000000, 0x0008050000000000, 0x00110A0000000000, 0x0022140000000000,
+ 0x0044280000000000, 0x0088500000000000, 0x0010A00000000000, 0x0020400000000000};
// pre-calculated lookup table for king attacks
static constexpr Bitboard KingAttacks[64] = {
- 0x0000000000000302, 0x0000000000000705, 0x0000000000000E0A, 0x0000000000001C14, 0x0000000000003828,
- 0x0000000000007050, 0x000000000000E0A0, 0x000000000000C040, 0x0000000000030203, 0x0000000000070507,
- 0x00000000000E0A0E, 0x00000000001C141C, 0x0000000000382838, 0x0000000000705070, 0x0000000000E0A0E0,
- 0x0000000000C040C0, 0x0000000003020300, 0x0000000007050700, 0x000000000E0A0E00, 0x000000001C141C00,
- 0x0000000038283800, 0x0000000070507000, 0x00000000E0A0E000, 0x00000000C040C000, 0x0000000302030000,
- 0x0000000705070000, 0x0000000E0A0E0000, 0x0000001C141C0000, 0x0000003828380000, 0x0000007050700000,
- 0x000000E0A0E00000, 0x000000C040C00000, 0x0000030203000000, 0x0000070507000000, 0x00000E0A0E000000,
- 0x00001C141C000000, 0x0000382838000000, 0x0000705070000000, 0x0000E0A0E0000000, 0x0000C040C0000000,
- 0x0003020300000000, 0x0007050700000000, 0x000E0A0E00000000, 0x001C141C00000000, 0x0038283800000000,
- 0x0070507000000000, 0x00E0A0E000000000, 0x00C040C000000000, 0x0302030000000000, 0x0705070000000000,
- 0x0E0A0E0000000000, 0x1C141C0000000000, 0x3828380000000000, 0x7050700000000000, 0xE0A0E00000000000,
- 0xC040C00000000000, 0x0203000000000000, 0x0507000000000000, 0x0A0E000000000000, 0x141C000000000000,
- 0x2838000000000000, 0x5070000000000000, 0xA0E0000000000000, 0x40C0000000000000};
+ 0x0000000000000302, 0x0000000000000705, 0x0000000000000E0A, 0x0000000000001C14,
+ 0x0000000000003828, 0x0000000000007050, 0x000000000000E0A0, 0x000000000000C040,
+ 0x0000000000030203, 0x0000000000070507, 0x00000000000E0A0E, 0x00000000001C141C,
+ 0x0000000000382838, 0x0000000000705070, 0x0000000000E0A0E0, 0x0000000000C040C0,
+ 0x0000000003020300, 0x0000000007050700, 0x000000000E0A0E00, 0x000000001C141C00,
+ 0x0000000038283800, 0x0000000070507000, 0x00000000E0A0E000, 0x00000000C040C000,
+ 0x0000000302030000, 0x0000000705070000, 0x0000000E0A0E0000, 0x0000001C141C0000,
+ 0x0000003828380000, 0x0000007050700000, 0x000000E0A0E00000, 0x000000C040C00000,
+ 0x0000030203000000, 0x0000070507000000, 0x00000E0A0E000000, 0x00001C141C000000,
+ 0x0000382838000000, 0x0000705070000000, 0x0000E0A0E0000000, 0x0000C040C0000000,
+ 0x0003020300000000, 0x0007050700000000, 0x000E0A0E00000000, 0x001C141C00000000,
+ 0x0038283800000000, 0x0070507000000000, 0x00E0A0E000000000, 0x00C040C000000000,
+ 0x0302030000000000, 0x0705070000000000, 0x0E0A0E0000000000, 0x1C141C0000000000,
+ 0x3828380000000000, 0x7050700000000000, 0xE0A0E00000000000, 0xC040C00000000000,
+ 0x0203000000000000, 0x0507000000000000, 0x0A0E000000000000, 0x141C000000000000,
+ 0x2838000000000000, 0x5070000000000000, 0xA0E0000000000000, 0x40C0000000000000};
static constexpr U64 RookMagics[64] = {
- 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};
+ 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};
static constexpr U64 BishopMagics[64] = {
- 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};
+ 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};
static inline Bitboard RookAttacks[0x19000] = {};
static inline Bitboard BishopAttacks[0x1480] = {};
@@ -1087,12 +1191,13 @@ class attacks {
static inline Magic BishopTable[64] = {};
public:
- static constexpr Bitboard MASK_RANK[8] = {0xff, 0xff00, 0xff0000, 0xff000000,
- 0xff00000000, 0xff0000000000, 0xff000000000000, 0xff00000000000000};
+ static constexpr Bitboard MASK_RANK[8] = {
+ 0xff, 0xff00, 0xff0000, 0xff000000,
+ 0xff00000000, 0xff0000000000, 0xff000000000000, 0xff00000000000000};
static constexpr Bitboard MASK_FILE[8] = {
- 0x101010101010101, 0x202020202020202, 0x404040404040404, 0x808080808080808,
- 0x1010101010101010, 0x2020202020202020, 0x4040404040404040, 0x8080808080808080,
+ 0x101010101010101, 0x202020202020202, 0x404040404040404, 0x808080808080808,
+ 0x1010101010101010, 0x2020202020202020, 0x4040404040404040, 0x8080808080808080,
};
/**
@@ -1101,7 +1206,7 @@ class attacks {
* @param b
* @return
*/
- template
+ template
[[nodiscard]] static constexpr Bitboard shift(const Bitboard b);
/**
@@ -1110,7 +1215,7 @@ class attacks {
* @param pawns
* @return
*/
- template
+ template
[[nodiscard]] static Bitboard pawnLeftAttacks(const Bitboard pawns);
/**
@@ -1119,7 +1224,7 @@ class attacks {
* @param pawns
* @return
*/
- template
+ template
[[nodiscard]] static Bitboard pawnRightAttacks(const Bitboard pawns);
/**
@@ -1169,13 +1274,14 @@ class attacks {
[[nodiscard]] static Bitboard king(Square sq) noexcept;
/**
- * @brief Returns the attacks for a given piece on a given square
+ * @brief Returns the origin squares of pieces of a given color attacking a target square
* @param board
- * @param color
- * @param square
+ * @param color Attacker Color
+ * @param square Attacked Square
* @return
*/
- [[nodiscard]] static Bitboard attackers(const Board &board, Color color, Square square) noexcept;
+ [[nodiscard]] static Bitboard
+ attackers(const Board& board, Color color, Square square) noexcept;
/**
* @brief Returns the slider attacks for a given square
@@ -1184,7 +1290,7 @@ class attacks {
* @tparam pt
* @return
*/
- template
+ template
[[nodiscard]] static Bitboard slider(Square sq, Bitboard occupied) noexcept;
/**
@@ -1200,29 +1306,29 @@ class attacks {
// check if charconv header is available
#if __has_include()
-# define CHESS_USE_CHARCONV
-# include
+ #define CHESS_USE_CHARCONV
+ #include
#else
-# include
+ #include
#endif
-
namespace chess::constants {
constexpr Bitboard DEFAULT_CHECKMASK = Bitboard(0xFFFFFFFFFFFFFFFFull);
-constexpr auto STARTPOS = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
-constexpr auto MAX_MOVES = 256;
+constexpr auto STARTPOS = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+constexpr auto MAX_MOVES = 256;
} // namespace chess::constants
-
namespace chess {
class Move {
public:
Move() = default;
- constexpr Move(std::uint16_t move) : move_(move), score_(0) {}
+ constexpr Move(std::uint16_t move) :
+ move_(move),
+ score_(0) {}
/**
* @brief Creates a move from a source and target square.
@@ -1232,11 +1338,13 @@ class Move {
* @param pt leave this empty if it is not a promotion move, otherwise pass the piece type of the new piece.
* @return
*/
- template
- [[nodiscard]] static constexpr Move make(Square source, Square target, PieceType pt = PieceType::KNIGHT) noexcept {
+ template
+ [[nodiscard]] static constexpr Move
+ make(Square source, Square target, PieceType pt = PieceType::KNIGHT) noexcept {
assert(pt >= PieceType(PieceType::KNIGHT) && pt <= PieceType(PieceType::QUEEN));
- std::uint16_t bits_promotion = static_cast(pt - PieceType(PieceType::KNIGHT));
+ std::uint16_t bits_promotion =
+ static_cast(pt - PieceType(PieceType::KNIGHT));
return Move(MoveType + (bits_promotion << 12) + (source.index() << 6) + target.index());
}
@@ -1245,7 +1353,9 @@ class Move {
* @brief Get the source square of the move.
* @return
*/
- [[nodiscard]] constexpr Square from() const noexcept { return static_cast((move_ >> 6) & 0x3F); }
+ [[nodiscard]] constexpr Square from() const noexcept {
+ return static_cast((move_ >> 6) & 0x3F);
+ }
/**
* @brief Get the target square of the move.
@@ -1266,7 +1376,8 @@ class Move {
* @return
*/
[[nodiscard]] constexpr PieceType promotionType() const noexcept {
- return static_cast(((move_ >> 12) & 3) + PieceType(PieceType::KNIGHT));
+ return static_cast(((move_ >> 12) & 3)
+ + PieceType(PieceType::KNIGHT));
}
/**
@@ -1276,10 +1387,10 @@ class Move {
constexpr void setScore(std::int16_t score) noexcept { score_ = score; }
[[nodiscard]] constexpr std::uint16_t move() const noexcept { return move_; }
- [[nodiscard]] constexpr std::int16_t score() const noexcept { return score_; }
+ [[nodiscard]] constexpr std::int16_t score() const noexcept { return score_; }
- constexpr bool operator==(const Move &rhs) const noexcept { return move_ == rhs.move_; }
- constexpr bool operator!=(const Move &rhs) const noexcept { return move_ != rhs.move_; }
+ constexpr bool operator==(const Move& rhs) const noexcept { return move_ == rhs.move_; }
+ constexpr bool operator!=(const Move& rhs) const noexcept { return move_ != rhs.move_; }
static constexpr std::uint16_t NO_MOVE = 0;
static constexpr std::uint16_t NULL_MOVE = 65;
@@ -1290,25 +1401,12 @@ class Move {
private:
std::uint16_t move_;
- std::int16_t score_;
+ std::int16_t score_;
};
-inline std::ostream &operator<<(std::ostream &os, const Move &move) {
- Square from_sq = move.from();
- Square to_sq = move.to();
-
- os << from_sq << to_sq;
-
- if (move.typeOf() == Move::PROMOTION) {
- os << static_cast(move.promotionType());
- }
-
- return os;
-}
} // namespace chess
-
#include
#include
#include
@@ -1334,40 +1432,32 @@ class Movelist {
// Element access
[[nodiscard]] constexpr reference at(size_type pos) {
-#ifndef CHESS_NO_EXCEPTIONS
- if (pos >= size_) {
- throw std::out_of_range("Movelist::at: pos (which is " + std::to_string(pos) + ") >= size (which is " +
- std::to_string(size_) + ")");
- }
-#endif
+ // pos out-of-range ignored
return moves_[pos];
}
[[nodiscard]] constexpr const_reference at(size_type pos) const {
-#ifndef CHESS_NO_EXCEPTIONS
- if (pos >= size_) {
- throw std::out_of_range("Movelist::at: pos (which is " + std::to_string(pos) + ") >= size (which is " +
- std::to_string(size_) + ")");
- }
-#endif
+ // pos out-of-range ignored
return moves_[pos];
}
[[nodiscard]] constexpr reference operator[](size_type pos) noexcept { return moves_[pos]; }
- [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept { return moves_[pos]; }
+ [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept {
+ return moves_[pos];
+ }
- [[nodiscard]] constexpr reference front() noexcept { return moves_[0]; }
+ [[nodiscard]] constexpr reference front() noexcept { return moves_[0]; }
[[nodiscard]] constexpr const_reference front() const noexcept { return moves_[0]; }
- [[nodiscard]] constexpr reference back() noexcept { return moves_[size_ - 1]; }
+ [[nodiscard]] constexpr reference back() noexcept { return moves_[size_ - 1]; }
[[nodiscard]] constexpr const_reference back() const noexcept { return moves_[size_ - 1]; }
// Iterators
- [[nodiscard]] constexpr iterator begin() noexcept { return &moves_[0]; }
+ [[nodiscard]] constexpr iterator begin() noexcept { return &moves_[0]; }
[[nodiscard]] constexpr const_iterator begin() const noexcept { return &moves_[0]; }
- [[nodiscard]] constexpr iterator end() noexcept { return &moves_[0] + size_; }
+ [[nodiscard]] constexpr iterator end() noexcept { return &moves_[0] + size_; }
[[nodiscard]] constexpr const_iterator end() const noexcept { return &moves_[0] + size_; }
// Capacity
@@ -1416,9 +1506,12 @@ class Movelist {
* @param move
* @return
*/
- [[nodiscard]] [[deprecated("Use std::find() instead.")]] constexpr size_type find(value_type move) const noexcept {
- for (size_type i = 0; i < size_; ++i) {
- if (moves_[i] == move) {
+ [[nodiscard]] [[deprecated("Use std::find() instead.")]] constexpr size_type
+ find(value_type move) const noexcept {
+ for (size_type i = 0; i < size_; ++i)
+ {
+ if (moves_[i] == move)
+ {
return i;
}
}
@@ -1428,7 +1521,7 @@ class Movelist {
private:
std::array moves_;
- size_type size_ = 0;
+ size_type size_ = 0;
};
} // namespace chess
@@ -1446,7 +1539,11 @@ class Board;
class movegen {
public:
- enum class MoveGenType : std::uint8_t { ALL, CAPTURE, QUIET };
+ enum class MoveGenType : std::uint8_t {
+ ALL,
+ CAPTURE,
+ QUIET
+ };
/**
* @brief Generates all legal moves for a position.
@@ -1455,36 +1552,47 @@ class movegen {
* @param board
* @param pieces
*/
- template
- void static legalmoves(Movelist &movelist, const Board &board,
- int pieces = PieceGenType::PAWN | PieceGenType::KNIGHT | PieceGenType::BISHOP |
- PieceGenType::ROOK | PieceGenType::QUEEN | PieceGenType::KING);
+ template
+ void static legalmoves(Movelist& movelist,
+ const Board& board,
+ int pieces = PieceGenType::PAWN | PieceGenType::KNIGHT
+ | PieceGenType::BISHOP | PieceGenType::ROOK
+ | PieceGenType::QUEEN | PieceGenType::KING);
private:
- static auto init_squares_between();
+ static auto init_squares_between();
static const std::array, 64> SQUARES_BETWEEN_BB;
// Generate the checkmask. Returns a bitboard where the attacker path between the king and enemy piece is set.
- template
- [[nodiscard]] static std::pair checkMask(const Board &board, Square sq);
+ template
+ [[nodiscard]] static std::pair checkMask(const Board& board, Square sq);
// Generate the pin mask for horizontal and vertical pins -> PieceType::ROOK
// Generate the pin mask for diagonal pins. -> PieceType::BISHOP
// Returns a bitboard where the ray between the king and the pinner is set.
- template
- [[nodiscard]] static Bitboard pinMask(const Board &board, Square sq, Bitboard occ_enemy, Bitboard occ_us) noexcept;
+ template
+ [[nodiscard]] static Bitboard
+ pinMask(const Board& board, Square sq, Bitboard occ_enemy, Bitboard occ_us) noexcept;
// Returns the squares that are attacked by the enemy
- template
- [[nodiscard]] static Bitboard seenSquares(const Board &board, Bitboard enemy_empty);
+ template
+ [[nodiscard]] static Bitboard seenSquares(const Board& board, Bitboard enemy_empty);
// Generate pawn moves.
- template
- static void generatePawnMoves(const Board &board, Movelist &moves, Bitboard pin_d, Bitboard pin_hv,
- Bitboard checkmask, Bitboard occ_enemy);
-
- [[nodiscard]] static std::array generateEPMove(const Board &board, Bitboard checkmask, Bitboard pin_d,
- Bitboard pawns_lr, Square ep, Color c);
+ template
+ static void generatePawnMoves(const Board& board,
+ Movelist& moves,
+ Bitboard pin_d,
+ Bitboard pin_hv,
+ Bitboard checkmask,
+ Bitboard occ_enemy);
+
+ [[nodiscard]] static std::array generateEPMove(const Board& board,
+ Bitboard checkmask,
+ Bitboard pin_d,
+ Bitboard pawns_lr,
+ Square ep,
+ Color c);
[[nodiscard]] static Bitboard generateKnightMoves(Square sq);
@@ -1492,21 +1600,24 @@ class movegen {
[[nodiscard]] static Bitboard generateRookMoves(Square sq, Bitboard pin_hv, Bitboard occ_all);
- [[nodiscard]] static Bitboard generateQueenMoves(Square sq, Bitboard pin_d, Bitboard pin_hv, Bitboard occ_all);
+ [[nodiscard]] static Bitboard
+ generateQueenMoves(Square sq, Bitboard pin_d, Bitboard pin_hv, Bitboard occ_all);
- [[nodiscard]] static Bitboard generateKingMoves(Square sq, Bitboard seen, Bitboard movable_square);
+ [[nodiscard]] static Bitboard
+ generateKingMoves(Square sq, Bitboard seen, Bitboard movable_square);
- template
- [[nodiscard]] static Bitboard generateCastleMoves(const Board &board, Square sq, Bitboard seen, Bitboard pinHV) noexcept;
+ template
+ [[nodiscard]] static Bitboard
+ generateCastleMoves(const Board& board, Square sq, Bitboard seen, Bitboard pinHV) noexcept;
- template
- static void whileBitboardAdd(Movelist &movelist, Bitboard mask, T func);
+ template
+ static void whileBitboardAdd(Movelist& movelist, Bitboard mask, T func);
- template
- static void legalmoves(Movelist &movelist, const Board &board, int pieces);
+ template
+ static void legalmoves(Movelist& movelist, const Board& board, int pieces);
- template
- static bool isEpSquareValid(const Board &board, Square ep);
+ template
+ static bool isEpSquareValid(const Board& board, Square ep);
[[nodiscard]] static Bitboard between(Square sq1, Square sq2) noexcept;
@@ -1516,168 +1627,206 @@ class movegen {
} // namespace chess
-
namespace chess {
class Zobrist {
using U64 = std::uint64_t;
static constexpr U64 RANDOM_ARRAY[781] = {
- 0x9D39247E33776D41, 0x2AF7398005AAA5C7, 0x44DB015024623547, 0x9C15F73E62A76AE2, 0x75834465489C0C89,
- 0x3290AC3A203001BF, 0x0FBBAD1F61042279, 0xE83A908FF2FB60CA, 0x0D7E765D58755C10, 0x1A083822CEAFE02D,
- 0x9605D5F0E25EC3B0, 0xD021FF5CD13A2ED5, 0x40BDF15D4A672E32, 0x011355146FD56395, 0x5DB4832046F3D9E5,
- 0x239F8B2D7FF719CC, 0x05D1A1AE85B49AA1, 0x679F848F6E8FC971, 0x7449BBFF801FED0B, 0x7D11CDB1C3B7ADF0,
- 0x82C7709E781EB7CC, 0xF3218F1C9510786C, 0x331478F3AF51BBE6, 0x4BB38DE5E7219443, 0xAA649C6EBCFD50FC,
- 0x8DBD98A352AFD40B, 0x87D2074B81D79217, 0x19F3C751D3E92AE1, 0xB4AB30F062B19ABF, 0x7B0500AC42047AC4,
- 0xC9452CA81A09D85D, 0x24AA6C514DA27500, 0x4C9F34427501B447, 0x14A68FD73C910841, 0xA71B9B83461CBD93,
- 0x03488B95B0F1850F, 0x637B2B34FF93C040, 0x09D1BC9A3DD90A94, 0x3575668334A1DD3B, 0x735E2B97A4C45A23,
- 0x18727070F1BD400B, 0x1FCBACD259BF02E7, 0xD310A7C2CE9B6555, 0xBF983FE0FE5D8244, 0x9F74D14F7454A824,
- 0x51EBDC4AB9BA3035, 0x5C82C505DB9AB0FA, 0xFCF7FE8A3430B241, 0x3253A729B9BA3DDE, 0x8C74C368081B3075,
- 0xB9BC6C87167C33E7, 0x7EF48F2B83024E20, 0x11D505D4C351BD7F, 0x6568FCA92C76A243, 0x4DE0B0F40F32A7B8,
- 0x96D693460CC37E5D, 0x42E240CB63689F2F, 0x6D2BDCDAE2919661, 0x42880B0236E4D951, 0x5F0F4A5898171BB6,
- 0x39F890F579F92F88, 0x93C5B5F47356388B, 0x63DC359D8D231B78, 0xEC16CA8AEA98AD76, 0x5355F900C2A82DC7,
- 0x07FB9F855A997142, 0x5093417AA8A7ED5E, 0x7BCBC38DA25A7F3C, 0x19FC8A768CF4B6D4, 0x637A7780DECFC0D9,
- 0x8249A47AEE0E41F7, 0x79AD695501E7D1E8, 0x14ACBAF4777D5776, 0xF145B6BECCDEA195, 0xDABF2AC8201752FC,
- 0x24C3C94DF9C8D3F6, 0xBB6E2924F03912EA, 0x0CE26C0B95C980D9, 0xA49CD132BFBF7CC4, 0xE99D662AF4243939,
- 0x27E6AD7891165C3F, 0x8535F040B9744FF1, 0x54B3F4FA5F40D873, 0x72B12C32127FED2B, 0xEE954D3C7B411F47,
- 0x9A85AC909A24EAA1, 0x70AC4CD9F04F21F5, 0xF9B89D3E99A075C2, 0x87B3E2B2B5C907B1, 0xA366E5B8C54F48B8,
- 0xAE4A9346CC3F7CF2, 0x1920C04D47267BBD, 0x87BF02C6B49E2AE9, 0x092237AC237F3859, 0xFF07F64EF8ED14D0,
- 0x8DE8DCA9F03CC54E, 0x9C1633264DB49C89, 0xB3F22C3D0B0B38ED, 0x390E5FB44D01144B, 0x5BFEA5B4712768E9,
- 0x1E1032911FA78984, 0x9A74ACB964E78CB3, 0x4F80F7A035DAFB04, 0x6304D09A0B3738C4, 0x2171E64683023A08,
- 0x5B9B63EB9CEFF80C, 0x506AACF489889342, 0x1881AFC9A3A701D6, 0x6503080440750644, 0xDFD395339CDBF4A7,
- 0xEF927DBCF00C20F2, 0x7B32F7D1E03680EC, 0xB9FD7620E7316243, 0x05A7E8A57DB91B77, 0xB5889C6E15630A75,
- 0x4A750A09CE9573F7, 0xCF464CEC899A2F8A, 0xF538639CE705B824, 0x3C79A0FF5580EF7F, 0xEDE6C87F8477609D,
- 0x799E81F05BC93F31, 0x86536B8CF3428A8C, 0x97D7374C60087B73, 0xA246637CFF328532, 0x043FCAE60CC0EBA0,
- 0x920E449535DD359E, 0x70EB093B15B290CC, 0x73A1921916591CBD, 0x56436C9FE1A1AA8D, 0xEFAC4B70633B8F81,
- 0xBB215798D45DF7AF, 0x45F20042F24F1768, 0x930F80F4E8EB7462, 0xFF6712FFCFD75EA1, 0xAE623FD67468AA70,
- 0xDD2C5BC84BC8D8FC, 0x7EED120D54CF2DD9, 0x22FE545401165F1C, 0xC91800E98FB99929, 0x808BD68E6AC10365,
- 0xDEC468145B7605F6, 0x1BEDE3A3AEF53302, 0x43539603D6C55602, 0xAA969B5C691CCB7A, 0xA87832D392EFEE56,
- 0x65942C7B3C7E11AE, 0xDED2D633CAD004F6, 0x21F08570F420E565, 0xB415938D7DA94E3C, 0x91B859E59ECB6350,
- 0x10CFF333E0ED804A, 0x28AED140BE0BB7DD, 0xC5CC1D89724FA456, 0x5648F680F11A2741, 0x2D255069F0B7DAB3,
- 0x9BC5A38EF729ABD4, 0xEF2F054308F6A2BC, 0xAF2042F5CC5C2858, 0x480412BAB7F5BE2A, 0xAEF3AF4A563DFE43,
- 0x19AFE59AE451497F, 0x52593803DFF1E840, 0xF4F076E65F2CE6F0, 0x11379625747D5AF3, 0xBCE5D2248682C115,
- 0x9DA4243DE836994F, 0x066F70B33FE09017, 0x4DC4DE189B671A1C, 0x51039AB7712457C3, 0xC07A3F80C31FB4B4,
- 0xB46EE9C5E64A6E7C, 0xB3819A42ABE61C87, 0x21A007933A522A20, 0x2DF16F761598AA4F, 0x763C4A1371B368FD,
- 0xF793C46702E086A0, 0xD7288E012AEB8D31, 0xDE336A2A4BC1C44B, 0x0BF692B38D079F23, 0x2C604A7A177326B3,
- 0x4850E73E03EB6064, 0xCFC447F1E53C8E1B, 0xB05CA3F564268D99, 0x9AE182C8BC9474E8, 0xA4FC4BD4FC5558CA,
- 0xE755178D58FC4E76, 0x69B97DB1A4C03DFE, 0xF9B5B7C4ACC67C96, 0xFC6A82D64B8655FB, 0x9C684CB6C4D24417,
- 0x8EC97D2917456ED0, 0x6703DF9D2924E97E, 0xC547F57E42A7444E, 0x78E37644E7CAD29E, 0xFE9A44E9362F05FA,
- 0x08BD35CC38336615, 0x9315E5EB3A129ACE, 0x94061B871E04DF75, 0xDF1D9F9D784BA010, 0x3BBA57B68871B59D,
- 0xD2B7ADEEDED1F73F, 0xF7A255D83BC373F8, 0xD7F4F2448C0CEB81, 0xD95BE88CD210FFA7, 0x336F52F8FF4728E7,
- 0xA74049DAC312AC71, 0xA2F61BB6E437FDB5, 0x4F2A5CB07F6A35B3, 0x87D380BDA5BF7859, 0x16B9F7E06C453A21,
- 0x7BA2484C8A0FD54E, 0xF3A678CAD9A2E38C, 0x39B0BF7DDE437BA2, 0xFCAF55C1BF8A4424, 0x18FCF680573FA594,
- 0x4C0563B89F495AC3, 0x40E087931A00930D, 0x8CFFA9412EB642C1, 0x68CA39053261169F, 0x7A1EE967D27579E2,
- 0x9D1D60E5076F5B6F, 0x3810E399B6F65BA2, 0x32095B6D4AB5F9B1, 0x35CAB62109DD038A, 0xA90B24499FCFAFB1,
- 0x77A225A07CC2C6BD, 0x513E5E634C70E331, 0x4361C0CA3F692F12, 0xD941ACA44B20A45B, 0x528F7C8602C5807B,
- 0x52AB92BEB9613989, 0x9D1DFA2EFC557F73, 0x722FF175F572C348, 0x1D1260A51107FE97, 0x7A249A57EC0C9BA2,
- 0x04208FE9E8F7F2D6, 0x5A110C6058B920A0, 0x0CD9A497658A5698, 0x56FD23C8F9715A4C, 0x284C847B9D887AAE,
- 0x04FEABFBBDB619CB, 0x742E1E651C60BA83, 0x9A9632E65904AD3C, 0x881B82A13B51B9E2, 0x506E6744CD974924,
- 0xB0183DB56FFC6A79, 0x0ED9B915C66ED37E, 0x5E11E86D5873D484, 0xF678647E3519AC6E, 0x1B85D488D0F20CC5,
- 0xDAB9FE6525D89021, 0x0D151D86ADB73615, 0xA865A54EDCC0F019, 0x93C42566AEF98FFB, 0x99E7AFEABE000731,
- 0x48CBFF086DDF285A, 0x7F9B6AF1EBF78BAF, 0x58627E1A149BBA21, 0x2CD16E2ABD791E33, 0xD363EFF5F0977996,
- 0x0CE2A38C344A6EED, 0x1A804AADB9CFA741, 0x907F30421D78C5DE, 0x501F65EDB3034D07, 0x37624AE5A48FA6E9,
- 0x957BAF61700CFF4E, 0x3A6C27934E31188A, 0xD49503536ABCA345, 0x088E049589C432E0, 0xF943AEE7FEBF21B8,
- 0x6C3B8E3E336139D3, 0x364F6FFA464EE52E, 0xD60F6DCEDC314222, 0x56963B0DCA418FC0, 0x16F50EDF91E513AF,
- 0xEF1955914B609F93, 0x565601C0364E3228, 0xECB53939887E8175, 0xBAC7A9A18531294B, 0xB344C470397BBA52,
- 0x65D34954DAF3CEBD, 0xB4B81B3FA97511E2, 0xB422061193D6F6A7, 0x071582401C38434D, 0x7A13F18BBEDC4FF5,
- 0xBC4097B116C524D2, 0x59B97885E2F2EA28, 0x99170A5DC3115544, 0x6F423357E7C6A9F9, 0x325928EE6E6F8794,
- 0xD0E4366228B03343, 0x565C31F7DE89EA27, 0x30F5611484119414, 0xD873DB391292ED4F, 0x7BD94E1D8E17DEBC,
- 0xC7D9F16864A76E94, 0x947AE053EE56E63C, 0xC8C93882F9475F5F, 0x3A9BF55BA91F81CA, 0xD9A11FBB3D9808E4,
- 0x0FD22063EDC29FCA, 0xB3F256D8ACA0B0B9, 0xB03031A8B4516E84, 0x35DD37D5871448AF, 0xE9F6082B05542E4E,
- 0xEBFAFA33D7254B59, 0x9255ABB50D532280, 0xB9AB4CE57F2D34F3, 0x693501D628297551, 0xC62C58F97DD949BF,
- 0xCD454F8F19C5126A, 0xBBE83F4ECC2BDECB, 0xDC842B7E2819E230, 0xBA89142E007503B8, 0xA3BC941D0A5061CB,
- 0xE9F6760E32CD8021, 0x09C7E552BC76492F, 0x852F54934DA55CC9, 0x8107FCCF064FCF56, 0x098954D51FFF6580,
- 0x23B70EDB1955C4BF, 0xC330DE426430F69D, 0x4715ED43E8A45C0A, 0xA8D7E4DAB780A08D, 0x0572B974F03CE0BB,
- 0xB57D2E985E1419C7, 0xE8D9ECBE2CF3D73F, 0x2FE4B17170E59750, 0x11317BA87905E790, 0x7FBF21EC8A1F45EC,
- 0x1725CABFCB045B00, 0x964E915CD5E2B207, 0x3E2B8BCBF016D66D, 0xBE7444E39328A0AC, 0xF85B2B4FBCDE44B7,
- 0x49353FEA39BA63B1, 0x1DD01AAFCD53486A, 0x1FCA8A92FD719F85, 0xFC7C95D827357AFA, 0x18A6A990C8B35EBD,
- 0xCCCB7005C6B9C28D, 0x3BDBB92C43B17F26, 0xAA70B5B4F89695A2, 0xE94C39A54A98307F, 0xB7A0B174CFF6F36E,
- 0xD4DBA84729AF48AD, 0x2E18BC1AD9704A68, 0x2DE0966DAF2F8B1C, 0xB9C11D5B1E43A07E, 0x64972D68DEE33360,
- 0x94628D38D0C20584, 0xDBC0D2B6AB90A559, 0xD2733C4335C6A72F, 0x7E75D99D94A70F4D, 0x6CED1983376FA72B,
- 0x97FCAACBF030BC24, 0x7B77497B32503B12, 0x8547EDDFB81CCB94, 0x79999CDFF70902CB, 0xCFFE1939438E9B24,
- 0x829626E3892D95D7, 0x92FAE24291F2B3F1, 0x63E22C147B9C3403, 0xC678B6D860284A1C, 0x5873888850659AE7,
- 0x0981DCD296A8736D, 0x9F65789A6509A440, 0x9FF38FED72E9052F, 0xE479EE5B9930578C, 0xE7F28ECD2D49EECD,
- 0x56C074A581EA17FE, 0x5544F7D774B14AEF, 0x7B3F0195FC6F290F, 0x12153635B2C0CF57, 0x7F5126DBBA5E0CA7,
- 0x7A76956C3EAFB413, 0x3D5774A11D31AB39, 0x8A1B083821F40CB4, 0x7B4A38E32537DF62, 0x950113646D1D6E03,
- 0x4DA8979A0041E8A9, 0x3BC36E078F7515D7, 0x5D0A12F27AD310D1, 0x7F9D1A2E1EBE1327, 0xDA3A361B1C5157B1,
- 0xDCDD7D20903D0C25, 0x36833336D068F707, 0xCE68341F79893389, 0xAB9090168DD05F34, 0x43954B3252DC25E5,
- 0xB438C2B67F98E5E9, 0x10DCD78E3851A492, 0xDBC27AB5447822BF, 0x9B3CDB65F82CA382, 0xB67B7896167B4C84,
- 0xBFCED1B0048EAC50, 0xA9119B60369FFEBD, 0x1FFF7AC80904BF45, 0xAC12FB171817EEE7, 0xAF08DA9177DDA93D,
- 0x1B0CAB936E65C744, 0xB559EB1D04E5E932, 0xC37B45B3F8D6F2BA, 0xC3A9DC228CAAC9E9, 0xF3B8B6675A6507FF,
- 0x9FC477DE4ED681DA, 0x67378D8ECCEF96CB, 0x6DD856D94D259236, 0xA319CE15B0B4DB31, 0x073973751F12DD5E,
- 0x8A8E849EB32781A5, 0xE1925C71285279F5, 0x74C04BF1790C0EFE, 0x4DDA48153C94938A, 0x9D266D6A1CC0542C,
- 0x7440FB816508C4FE, 0x13328503DF48229F, 0xD6BF7BAEE43CAC40, 0x4838D65F6EF6748F, 0x1E152328F3318DEA,
- 0x8F8419A348F296BF, 0x72C8834A5957B511, 0xD7A023A73260B45C, 0x94EBC8ABCFB56DAE, 0x9FC10D0F989993E0,
- 0xDE68A2355B93CAE6, 0xA44CFE79AE538BBE, 0x9D1D84FCCE371425, 0x51D2B1AB2DDFB636, 0x2FD7E4B9E72CD38C,
- 0x65CA5B96B7552210, 0xDD69A0D8AB3B546D, 0x604D51B25FBF70E2, 0x73AA8A564FB7AC9E, 0x1A8C1E992B941148,
- 0xAAC40A2703D9BEA0, 0x764DBEAE7FA4F3A6, 0x1E99B96E70A9BE8B, 0x2C5E9DEB57EF4743, 0x3A938FEE32D29981,
- 0x26E6DB8FFDF5ADFE, 0x469356C504EC9F9D, 0xC8763C5B08D1908C, 0x3F6C6AF859D80055, 0x7F7CC39420A3A545,
- 0x9BFB227EBDF4C5CE, 0x89039D79D6FC5C5C, 0x8FE88B57305E2AB6, 0xA09E8C8C35AB96DE, 0xFA7E393983325753,
- 0xD6B6D0ECC617C699, 0xDFEA21EA9E7557E3, 0xB67C1FA481680AF8, 0xCA1E3785A9E724E5, 0x1CFC8BED0D681639,
- 0xD18D8549D140CAEA, 0x4ED0FE7E9DC91335, 0xE4DBF0634473F5D2, 0x1761F93A44D5AEFE, 0x53898E4C3910DA55,
- 0x734DE8181F6EC39A, 0x2680B122BAA28D97, 0x298AF231C85BAFAB, 0x7983EED3740847D5, 0x66C1A2A1A60CD889,
- 0x9E17E49642A3E4C1, 0xEDB454E7BADC0805, 0x50B704CAB602C329, 0x4CC317FB9CDDD023, 0x66B4835D9EAFEA22,
- 0x219B97E26FFC81BD, 0x261E4E4C0A333A9D, 0x1FE2CCA76517DB90, 0xD7504DFA8816EDBB, 0xB9571FA04DC089C8,
- 0x1DDC0325259B27DE, 0xCF3F4688801EB9AA, 0xF4F5D05C10CAB243, 0x38B6525C21A42B0E, 0x36F60E2BA4FA6800,
- 0xEB3593803173E0CE, 0x9C4CD6257C5A3603, 0xAF0C317D32ADAA8A, 0x258E5A80C7204C4B, 0x8B889D624D44885D,
- 0xF4D14597E660F855, 0xD4347F66EC8941C3, 0xE699ED85B0DFB40D, 0x2472F6207C2D0484, 0xC2A1E7B5B459AEB5,
- 0xAB4F6451CC1D45EC, 0x63767572AE3D6174, 0xA59E0BD101731A28, 0x116D0016CB948F09, 0x2CF9C8CA052F6E9F,
- 0x0B090A7560A968E3, 0xABEEDDB2DDE06FF1, 0x58EFC10B06A2068D, 0xC6E57A78FBD986E0, 0x2EAB8CA63CE802D7,
- 0x14A195640116F336, 0x7C0828DD624EC390, 0xD74BBE77E6116AC7, 0x804456AF10F5FB53, 0xEBE9EA2ADF4321C7,
- 0x03219A39EE587A30, 0x49787FEF17AF9924, 0xA1E9300CD8520548, 0x5B45E522E4B1B4EF, 0xB49C3B3995091A36,
- 0xD4490AD526F14431, 0x12A8F216AF9418C2, 0x001F837CC7350524, 0x1877B51E57A764D5, 0xA2853B80F17F58EE,
- 0x993E1DE72D36D310, 0xB3598080CE64A656, 0x252F59CF0D9F04BB, 0xD23C8E176D113600, 0x1BDA0492E7E4586E,
- 0x21E0BD5026C619BF, 0x3B097ADAF088F94E, 0x8D14DEDB30BE846E, 0xF95CFFA23AF5F6F4, 0x3871700761B3F743,
- 0xCA672B91E9E4FA16, 0x64C8E531BFF53B55, 0x241260ED4AD1E87D, 0x106C09B972D2E822, 0x7FBA195410E5CA30,
- 0x7884D9BC6CB569D8, 0x0647DFEDCD894A29, 0x63573FF03E224774, 0x4FC8E9560F91B123, 0x1DB956E450275779,
- 0xB8D91274B9E9D4FB, 0xA2EBEE47E2FBFCE1, 0xD9F1F30CCD97FB09, 0xEFED53D75FD64E6B, 0x2E6D02C36017F67F,
- 0xA9AA4D20DB084E9B, 0xB64BE8D8B25396C1, 0x70CB6AF7C2D5BCF0, 0x98F076A4F7A2322E, 0xBF84470805E69B5F,
- 0x94C3251F06F90CF3, 0x3E003E616A6591E9, 0xB925A6CD0421AFF3, 0x61BDD1307C66E300, 0xBF8D5108E27E0D48,
- 0x240AB57A8B888B20, 0xFC87614BAF287E07, 0xEF02CDD06FFDB432, 0xA1082C0466DF6C0A, 0x8215E577001332C8,
- 0xD39BB9C3A48DB6CF, 0x2738259634305C14, 0x61CF4F94C97DF93D, 0x1B6BACA2AE4E125B, 0x758F450C88572E0B,
- 0x959F587D507A8359, 0xB063E962E045F54D, 0x60E8ED72C0DFF5D1, 0x7B64978555326F9F, 0xFD080D236DA814BA,
- 0x8C90FD9B083F4558, 0x106F72FE81E2C590, 0x7976033A39F7D952, 0xA4EC0132764CA04B, 0x733EA705FAE4FA77,
- 0xB4D8F77BC3E56167, 0x9E21F4F903B33FD9, 0x9D765E419FB69F6D, 0xD30C088BA61EA5EF, 0x5D94337FBFAF7F5B,
- 0x1A4E4822EB4D7A59, 0x6FFE73E81B637FB3, 0xDDF957BC36D8B9CA, 0x64D0E29EEA8838B3, 0x08DD9BDFD96B9F63,
- 0x087E79E5A57D1D13, 0xE328E230E3E2B3FB, 0x1C2559E30F0946BE, 0x720BF5F26F4D2EAA, 0xB0774D261CC609DB,
- 0x443F64EC5A371195, 0x4112CF68649A260E, 0xD813F2FAB7F5C5CA, 0x660D3257380841EE, 0x59AC2C7873F910A3,
- 0xE846963877671A17, 0x93B633ABFA3469F8, 0xC0C0F5A60EF4CDCF, 0xCAF21ECD4377B28C, 0x57277707199B8175,
- 0x506C11B9D90E8B1D, 0xD83CC2687A19255F, 0x4A29C6465A314CD1, 0xED2DF21216235097, 0xB5635C95FF7296E2,
- 0x22AF003AB672E811, 0x52E762596BF68235, 0x9AEBA33AC6ECC6B0, 0x944F6DE09134DFB6, 0x6C47BEC883A7DE39,
- 0x6AD047C430A12104, 0xA5B1CFDBA0AB4067, 0x7C45D833AFF07862, 0x5092EF950A16DA0B, 0x9338E69C052B8E7B,
- 0x455A4B4CFE30E3F5, 0x6B02E63195AD0CF8, 0x6B17B224BAD6BF27, 0xD1E0CCD25BB9C169, 0xDE0C89A556B9AE70,
- 0x50065E535A213CF6, 0x9C1169FA2777B874, 0x78EDEFD694AF1EED, 0x6DC93D9526A50E68, 0xEE97F453F06791ED,
- 0x32AB0EDB696703D3, 0x3A6853C7E70757A7, 0x31865CED6120F37D, 0x67FEF95D92607890, 0x1F2B1D1F15F6DC9C,
- 0xB69E38A8965C6B65, 0xAA9119FF184CCCF4, 0xF43C732873F24C13, 0xFB4A3D794A9A80D2, 0x3550C2321FD6109C,
- 0x371F77E76BB8417E, 0x6BFA9AAE5EC05779, 0xCD04F3FF001A4778, 0xE3273522064480CA, 0x9F91508BFFCFC14A,
- 0x049A7F41061A9E60, 0xFCB6BE43A9F2FE9B, 0x08DE8A1C7797DA9B, 0x8F9887E6078735A1, 0xB5B4071DBFC73A66,
- 0x230E343DFBA08D33, 0x43ED7F5A0FAE657D, 0x3A88A0FBBCB05C63, 0x21874B8B4D2DBC4F, 0x1BDEA12E35F6A8C9,
- 0x53C065C6C8E63528, 0xE34A1D250E7A8D6B, 0xD6B04D3B7651DD7E, 0x5E90277E7CB39E2D, 0x2C046F22062DC67D,
- 0xB10BB459132D0A26, 0x3FA9DDFB67E2F199, 0x0E09B88E1914F7AF, 0x10E8B35AF3EEAB37, 0x9EEDECA8E272B933,
- 0xD4C718BC4AE8AE5F, 0x81536D601170FC20, 0x91B534F885818A06, 0xEC8177F83F900978, 0x190E714FADA5156E,
- 0xB592BF39B0364963, 0x89C350C893AE7DC1, 0xAC042E70F8B383F2, 0xB49B52E587A1EE60, 0xFB152FE3FF26DA89,
- 0x3E666E6F69AE2C15, 0x3B544EBE544C19F9, 0xE805A1E290CF2456, 0x24B33C9D7ED25117, 0xE74733427B72F0C1,
- 0x0A804D18B7097475, 0x57E3306D881EDB4F, 0x4AE7D6A36EB5DBCB, 0x2D8D5432157064C8, 0xD1E649DE1E7F268B,
- 0x8A328A1CEDFE552C, 0x07A3AEC79624C7DA, 0x84547DDC3E203C94, 0x990A98FD5071D263, 0x1A4FF12616EEFC89,
- 0xF6F7FD1431714200, 0x30C05B1BA332F41C, 0x8D2636B81555A786, 0x46C9FEB55D120902, 0xCCEC0A73B49C9921,
- 0x4E9D2827355FC492, 0x19EBB029435DCB0F, 0x4659D2B743848A2C, 0x963EF2C96B33BE31, 0x74F85198B05A2E7D,
- 0x5A0F544DD2B1FB18, 0x03727073C2E134B1, 0xC7F6AA2DE59AEA61, 0x352787BAA0D7C22F, 0x9853EAB63B5E0B35,
- 0xABBDCDD7ED5C0860, 0xCF05DAF5AC8D77B0, 0x49CAD48CEBF4A71E, 0x7A4C10EC2158C4A6, 0xD9E92AA246BF719E,
- 0x13AE978D09FE5557, 0x730499AF921549FF, 0x4E4B705B92903BA4, 0xFF577222C14F0A3A, 0x55B6344CF97AAFAE,
- 0xB862225B055B6960, 0xCAC09AFBDDD2CDB4, 0xDAF8E9829FE96B5F, 0xB5FDFC5D3132C498, 0x310CB380DB6F7503,
- 0xE87FBB46217A360E, 0x2102AE466EBB1148, 0xF8549E1A3AA5E00D, 0x07A69AFDCC42261A, 0xC4C118BFE78FEAAE,
- 0xF9F4892ED96BD438, 0x1AF3DBE25D8F45DA, 0xF5B4B0B0D2DEEEB4, 0x962ACEEFA82E1C84, 0x046E3ECAAF453CE9,
- 0xF05D129681949A4C, 0x964781CE734B3C84, 0x9C2ED44081CE5FBD, 0x522E23F3925E319E, 0x177E00F9FC32F791,
- 0x2BC60A63A6F3B3F2, 0x222BBFAE61725606, 0x486289DDCC3D6780, 0x7DC7785B8EFDFC80, 0x8AF38731C02BA980,
- 0x1FAB64EA29A2DDF7, 0xE4D9429322CD065A, 0x9DA058C67844F20C, 0x24C0E332B70019B0, 0x233003B5A6CFE6AD,
- 0xD586BD01C5C217F6, 0x5E5637885F29BC2B, 0x7EBA726D8C94094B, 0x0A56A5F0BFE39272, 0xD79476A84EE20D06,
- 0x9E4C1269BAA4BF37, 0x17EFEE45B0DEE640, 0x1D95B0A5FCF90BC6, 0x93CBE0B699C2585D, 0x65FA4F227A2B6D79,
- 0xD5F9E858292504D5, 0xC2B5A03F71471A6F, 0x59300222B4561E00, 0xCE2F8642CA0712DC, 0x7CA9723FBB2E8988,
- 0x2785338347F2BA08, 0xC61BB3A141E50E8C, 0x150F361DAB9DEC26, 0x9F6A419D382595F4, 0x64A53DC924FE7AC9,
- 0x142DE49FFF7A7C3D, 0x0C335248857FA9E7, 0x0A9C32D5EAE45305, 0xE6C42178C4BBB92E, 0x71F1CE2490D20B07,
- 0xF1BCC3D275AFE51A, 0xE728E8C83C334074, 0x96FBF83A12884624, 0x81A1549FD6573DA5, 0x5FA7867CAF35E149,
- 0x56986E2EF3ED091B, 0x917F1DD5F8886C61, 0xD20D8C88C8FFE65F, 0x31D71DCE64B2C310, 0xF165B587DF898190,
- 0xA57E6339DD2CF3A0, 0x1EF6E6DBB1961EC9, 0x70CC73D90BC26E24, 0xE21A6B35DF0C3AD7, 0x003A93D8B2806962,
- 0x1C99DED33CB890A1, 0xCF3145DE0ADD4289, 0xD0E4427A5514FB72, 0x77C621CC9FB3A483, 0x67A34DAC4356550B,
- 0xF8D626AAAF278509};
+ 0x9D39247E33776D41, 0x2AF7398005AAA5C7, 0x44DB015024623547, 0x9C15F73E62A76AE2,
+ 0x75834465489C0C89, 0x3290AC3A203001BF, 0x0FBBAD1F61042279, 0xE83A908FF2FB60CA,
+ 0x0D7E765D58755C10, 0x1A083822CEAFE02D, 0x9605D5F0E25EC3B0, 0xD021FF5CD13A2ED5,
+ 0x40BDF15D4A672E32, 0x011355146FD56395, 0x5DB4832046F3D9E5, 0x239F8B2D7FF719CC,
+ 0x05D1A1AE85B49AA1, 0x679F848F6E8FC971, 0x7449BBFF801FED0B, 0x7D11CDB1C3B7ADF0,
+ 0x82C7709E781EB7CC, 0xF3218F1C9510786C, 0x331478F3AF51BBE6, 0x4BB38DE5E7219443,
+ 0xAA649C6EBCFD50FC, 0x8DBD98A352AFD40B, 0x87D2074B81D79217, 0x19F3C751D3E92AE1,
+ 0xB4AB30F062B19ABF, 0x7B0500AC42047AC4, 0xC9452CA81A09D85D, 0x24AA6C514DA27500,
+ 0x4C9F34427501B447, 0x14A68FD73C910841, 0xA71B9B83461CBD93, 0x03488B95B0F1850F,
+ 0x637B2B34FF93C040, 0x09D1BC9A3DD90A94, 0x3575668334A1DD3B, 0x735E2B97A4C45A23,
+ 0x18727070F1BD400B, 0x1FCBACD259BF02E7, 0xD310A7C2CE9B6555, 0xBF983FE0FE5D8244,
+ 0x9F74D14F7454A824, 0x51EBDC4AB9BA3035, 0x5C82C505DB9AB0FA, 0xFCF7FE8A3430B241,
+ 0x3253A729B9BA3DDE, 0x8C74C368081B3075, 0xB9BC6C87167C33E7, 0x7EF48F2B83024E20,
+ 0x11D505D4C351BD7F, 0x6568FCA92C76A243, 0x4DE0B0F40F32A7B8, 0x96D693460CC37E5D,
+ 0x42E240CB63689F2F, 0x6D2BDCDAE2919661, 0x42880B0236E4D951, 0x5F0F4A5898171BB6,
+ 0x39F890F579F92F88, 0x93C5B5F47356388B, 0x63DC359D8D231B78, 0xEC16CA8AEA98AD76,
+ 0x5355F900C2A82DC7, 0x07FB9F855A997142, 0x5093417AA8A7ED5E, 0x7BCBC38DA25A7F3C,
+ 0x19FC8A768CF4B6D4, 0x637A7780DECFC0D9, 0x8249A47AEE0E41F7, 0x79AD695501E7D1E8,
+ 0x14ACBAF4777D5776, 0xF145B6BECCDEA195, 0xDABF2AC8201752FC, 0x24C3C94DF9C8D3F6,
+ 0xBB6E2924F03912EA, 0x0CE26C0B95C980D9, 0xA49CD132BFBF7CC4, 0xE99D662AF4243939,
+ 0x27E6AD7891165C3F, 0x8535F040B9744FF1, 0x54B3F4FA5F40D873, 0x72B12C32127FED2B,
+ 0xEE954D3C7B411F47, 0x9A85AC909A24EAA1, 0x70AC4CD9F04F21F5, 0xF9B89D3E99A075C2,
+ 0x87B3E2B2B5C907B1, 0xA366E5B8C54F48B8, 0xAE4A9346CC3F7CF2, 0x1920C04D47267BBD,
+ 0x87BF02C6B49E2AE9, 0x092237AC237F3859, 0xFF07F64EF8ED14D0, 0x8DE8DCA9F03CC54E,
+ 0x9C1633264DB49C89, 0xB3F22C3D0B0B38ED, 0x390E5FB44D01144B, 0x5BFEA5B4712768E9,
+ 0x1E1032911FA78984, 0x9A74ACB964E78CB3, 0x4F80F7A035DAFB04, 0x6304D09A0B3738C4,
+ 0x2171E64683023A08, 0x5B9B63EB9CEFF80C, 0x506AACF489889342, 0x1881AFC9A3A701D6,
+ 0x6503080440750644, 0xDFD395339CDBF4A7, 0xEF927DBCF00C20F2, 0x7B32F7D1E03680EC,
+ 0xB9FD7620E7316243, 0x05A7E8A57DB91B77, 0xB5889C6E15630A75, 0x4A750A09CE9573F7,
+ 0xCF464CEC899A2F8A, 0xF538639CE705B824, 0x3C79A0FF5580EF7F, 0xEDE6C87F8477609D,
+ 0x799E81F05BC93F31, 0x86536B8CF3428A8C, 0x97D7374C60087B73, 0xA246637CFF328532,
+ 0x043FCAE60CC0EBA0, 0x920E449535DD359E, 0x70EB093B15B290CC, 0x73A1921916591CBD,
+ 0x56436C9FE1A1AA8D, 0xEFAC4B70633B8F81, 0xBB215798D45DF7AF, 0x45F20042F24F1768,
+ 0x930F80F4E8EB7462, 0xFF6712FFCFD75EA1, 0xAE623FD67468AA70, 0xDD2C5BC84BC8D8FC,
+ 0x7EED120D54CF2DD9, 0x22FE545401165F1C, 0xC91800E98FB99929, 0x808BD68E6AC10365,
+ 0xDEC468145B7605F6, 0x1BEDE3A3AEF53302, 0x43539603D6C55602, 0xAA969B5C691CCB7A,
+ 0xA87832D392EFEE56, 0x65942C7B3C7E11AE, 0xDED2D633CAD004F6, 0x21F08570F420E565,
+ 0xB415938D7DA94E3C, 0x91B859E59ECB6350, 0x10CFF333E0ED804A, 0x28AED140BE0BB7DD,
+ 0xC5CC1D89724FA456, 0x5648F680F11A2741, 0x2D255069F0B7DAB3, 0x9BC5A38EF729ABD4,
+ 0xEF2F054308F6A2BC, 0xAF2042F5CC5C2858, 0x480412BAB7F5BE2A, 0xAEF3AF4A563DFE43,
+ 0x19AFE59AE451497F, 0x52593803DFF1E840, 0xF4F076E65F2CE6F0, 0x11379625747D5AF3,
+ 0xBCE5D2248682C115, 0x9DA4243DE836994F, 0x066F70B33FE09017, 0x4DC4DE189B671A1C,
+ 0x51039AB7712457C3, 0xC07A3F80C31FB4B4, 0xB46EE9C5E64A6E7C, 0xB3819A42ABE61C87,
+ 0x21A007933A522A20, 0x2DF16F761598AA4F, 0x763C4A1371B368FD, 0xF793C46702E086A0,
+ 0xD7288E012AEB8D31, 0xDE336A2A4BC1C44B, 0x0BF692B38D079F23, 0x2C604A7A177326B3,
+ 0x4850E73E03EB6064, 0xCFC447F1E53C8E1B, 0xB05CA3F564268D99, 0x9AE182C8BC9474E8,
+ 0xA4FC4BD4FC5558CA, 0xE755178D58FC4E76, 0x69B97DB1A4C03DFE, 0xF9B5B7C4ACC67C96,
+ 0xFC6A82D64B8655FB, 0x9C684CB6C4D24417, 0x8EC97D2917456ED0, 0x6703DF9D2924E97E,
+ 0xC547F57E42A7444E, 0x78E37644E7CAD29E, 0xFE9A44E9362F05FA, 0x08BD35CC38336615,
+ 0x9315E5EB3A129ACE, 0x94061B871E04DF75, 0xDF1D9F9D784BA010, 0x3BBA57B68871B59D,
+ 0xD2B7ADEEDED1F73F, 0xF7A255D83BC373F8, 0xD7F4F2448C0CEB81, 0xD95BE88CD210FFA7,
+ 0x336F52F8FF4728E7, 0xA74049DAC312AC71, 0xA2F61BB6E437FDB5, 0x4F2A5CB07F6A35B3,
+ 0x87D380BDA5BF7859, 0x16B9F7E06C453A21, 0x7BA2484C8A0FD54E, 0xF3A678CAD9A2E38C,
+ 0x39B0BF7DDE437BA2, 0xFCAF55C1BF8A4424, 0x18FCF680573FA594, 0x4C0563B89F495AC3,
+ 0x40E087931A00930D, 0x8CFFA9412EB642C1, 0x68CA39053261169F, 0x7A1EE967D27579E2,
+ 0x9D1D60E5076F5B6F, 0x3810E399B6F65BA2, 0x32095B6D4AB5F9B1, 0x35CAB62109DD038A,
+ 0xA90B24499FCFAFB1, 0x77A225A07CC2C6BD, 0x513E5E634C70E331, 0x4361C0CA3F692F12,
+ 0xD941ACA44B20A45B, 0x528F7C8602C5807B, 0x52AB92BEB9613989, 0x9D1DFA2EFC557F73,
+ 0x722FF175F572C348, 0x1D1260A51107FE97, 0x7A249A57EC0C9BA2, 0x04208FE9E8F7F2D6,
+ 0x5A110C6058B920A0, 0x0CD9A497658A5698, 0x56FD23C8F9715A4C, 0x284C847B9D887AAE,
+ 0x04FEABFBBDB619CB, 0x742E1E651C60BA83, 0x9A9632E65904AD3C, 0x881B82A13B51B9E2,
+ 0x506E6744CD974924, 0xB0183DB56FFC6A79, 0x0ED9B915C66ED37E, 0x5E11E86D5873D484,
+ 0xF678647E3519AC6E, 0x1B85D488D0F20CC5, 0xDAB9FE6525D89021, 0x0D151D86ADB73615,
+ 0xA865A54EDCC0F019, 0x93C42566AEF98FFB, 0x99E7AFEABE000731, 0x48CBFF086DDF285A,
+ 0x7F9B6AF1EBF78BAF, 0x58627E1A149BBA21, 0x2CD16E2ABD791E33, 0xD363EFF5F0977996,
+ 0x0CE2A38C344A6EED, 0x1A804AADB9CFA741, 0x907F30421D78C5DE, 0x501F65EDB3034D07,
+ 0x37624AE5A48FA6E9, 0x957BAF61700CFF4E, 0x3A6C27934E31188A, 0xD49503536ABCA345,
+ 0x088E049589C432E0, 0xF943AEE7FEBF21B8, 0x6C3B8E3E336139D3, 0x364F6FFA464EE52E,
+ 0xD60F6DCEDC314222, 0x56963B0DCA418FC0, 0x16F50EDF91E513AF, 0xEF1955914B609F93,
+ 0x565601C0364E3228, 0xECB53939887E8175, 0xBAC7A9A18531294B, 0xB344C470397BBA52,
+ 0x65D34954DAF3CEBD, 0xB4B81B3FA97511E2, 0xB422061193D6F6A7, 0x071582401C38434D,
+ 0x7A13F18BBEDC4FF5, 0xBC4097B116C524D2, 0x59B97885E2F2EA28, 0x99170A5DC3115544,
+ 0x6F423357E7C6A9F9, 0x325928EE6E6F8794, 0xD0E4366228B03343, 0x565C31F7DE89EA27,
+ 0x30F5611484119414, 0xD873DB391292ED4F, 0x7BD94E1D8E17DEBC, 0xC7D9F16864A76E94,
+ 0x947AE053EE56E63C, 0xC8C93882F9475F5F, 0x3A9BF55BA91F81CA, 0xD9A11FBB3D9808E4,
+ 0x0FD22063EDC29FCA, 0xB3F256D8ACA0B0B9, 0xB03031A8B4516E84, 0x35DD37D5871448AF,
+ 0xE9F6082B05542E4E, 0xEBFAFA33D7254B59, 0x9255ABB50D532280, 0xB9AB4CE57F2D34F3,
+ 0x693501D628297551, 0xC62C58F97DD949BF, 0xCD454F8F19C5126A, 0xBBE83F4ECC2BDECB,
+ 0xDC842B7E2819E230, 0xBA89142E007503B8, 0xA3BC941D0A5061CB, 0xE9F6760E32CD8021,
+ 0x09C7E552BC76492F, 0x852F54934DA55CC9, 0x8107FCCF064FCF56, 0x098954D51FFF6580,
+ 0x23B70EDB1955C4BF, 0xC330DE426430F69D, 0x4715ED43E8A45C0A, 0xA8D7E4DAB780A08D,
+ 0x0572B974F03CE0BB, 0xB57D2E985E1419C7, 0xE8D9ECBE2CF3D73F, 0x2FE4B17170E59750,
+ 0x11317BA87905E790, 0x7FBF21EC8A1F45EC, 0x1725CABFCB045B00, 0x964E915CD5E2B207,
+ 0x3E2B8BCBF016D66D, 0xBE7444E39328A0AC, 0xF85B2B4FBCDE44B7, 0x49353FEA39BA63B1,
+ 0x1DD01AAFCD53486A, 0x1FCA8A92FD719F85, 0xFC7C95D827357AFA, 0x18A6A990C8B35EBD,
+ 0xCCCB7005C6B9C28D, 0x3BDBB92C43B17F26, 0xAA70B5B4F89695A2, 0xE94C39A54A98307F,
+ 0xB7A0B174CFF6F36E, 0xD4DBA84729AF48AD, 0x2E18BC1AD9704A68, 0x2DE0966DAF2F8B1C,
+ 0xB9C11D5B1E43A07E, 0x64972D68DEE33360, 0x94628D38D0C20584, 0xDBC0D2B6AB90A559,
+ 0xD2733C4335C6A72F, 0x7E75D99D94A70F4D, 0x6CED1983376FA72B, 0x97FCAACBF030BC24,
+ 0x7B77497B32503B12, 0x8547EDDFB81CCB94, 0x79999CDFF70902CB, 0xCFFE1939438E9B24,
+ 0x829626E3892D95D7, 0x92FAE24291F2B3F1, 0x63E22C147B9C3403, 0xC678B6D860284A1C,
+ 0x5873888850659AE7, 0x0981DCD296A8736D, 0x9F65789A6509A440, 0x9FF38FED72E9052F,
+ 0xE479EE5B9930578C, 0xE7F28ECD2D49EECD, 0x56C074A581EA17FE, 0x5544F7D774B14AEF,
+ 0x7B3F0195FC6F290F, 0x12153635B2C0CF57, 0x7F5126DBBA5E0CA7, 0x7A76956C3EAFB413,
+ 0x3D5774A11D31AB39, 0x8A1B083821F40CB4, 0x7B4A38E32537DF62, 0x950113646D1D6E03,
+ 0x4DA8979A0041E8A9, 0x3BC36E078F7515D7, 0x5D0A12F27AD310D1, 0x7F9D1A2E1EBE1327,
+ 0xDA3A361B1C5157B1, 0xDCDD7D20903D0C25, 0x36833336D068F707, 0xCE68341F79893389,
+ 0xAB9090168DD05F34, 0x43954B3252DC25E5, 0xB438C2B67F98E5E9, 0x10DCD78E3851A492,
+ 0xDBC27AB5447822BF, 0x9B3CDB65F82CA382, 0xB67B7896167B4C84, 0xBFCED1B0048EAC50,
+ 0xA9119B60369FFEBD, 0x1FFF7AC80904BF45, 0xAC12FB171817EEE7, 0xAF08DA9177DDA93D,
+ 0x1B0CAB936E65C744, 0xB559EB1D04E5E932, 0xC37B45B3F8D6F2BA, 0xC3A9DC228CAAC9E9,
+ 0xF3B8B6675A6507FF, 0x9FC477DE4ED681DA, 0x67378D8ECCEF96CB, 0x6DD856D94D259236,
+ 0xA319CE15B0B4DB31, 0x073973751F12DD5E, 0x8A8E849EB32781A5, 0xE1925C71285279F5,
+ 0x74C04BF1790C0EFE, 0x4DDA48153C94938A, 0x9D266D6A1CC0542C, 0x7440FB816508C4FE,
+ 0x13328503DF48229F, 0xD6BF7BAEE43CAC40, 0x4838D65F6EF6748F, 0x1E152328F3318DEA,
+ 0x8F8419A348F296BF, 0x72C8834A5957B511, 0xD7A023A73260B45C, 0x94EBC8ABCFB56DAE,
+ 0x9FC10D0F989993E0, 0xDE68A2355B93CAE6, 0xA44CFE79AE538BBE, 0x9D1D84FCCE371425,
+ 0x51D2B1AB2DDFB636, 0x2FD7E4B9E72CD38C, 0x65CA5B96B7552210, 0xDD69A0D8AB3B546D,
+ 0x604D51B25FBF70E2, 0x73AA8A564FB7AC9E, 0x1A8C1E992B941148, 0xAAC40A2703D9BEA0,
+ 0x764DBEAE7FA4F3A6, 0x1E99B96E70A9BE8B, 0x2C5E9DEB57EF4743, 0x3A938FEE32D29981,
+ 0x26E6DB8FFDF5ADFE, 0x469356C504EC9F9D, 0xC8763C5B08D1908C, 0x3F6C6AF859D80055,
+ 0x7F7CC39420A3A545, 0x9BFB227EBDF4C5CE, 0x89039D79D6FC5C5C, 0x8FE88B57305E2AB6,
+ 0xA09E8C8C35AB96DE, 0xFA7E393983325753, 0xD6B6D0ECC617C699, 0xDFEA21EA9E7557E3,
+ 0xB67C1FA481680AF8, 0xCA1E3785A9E724E5, 0x1CFC8BED0D681639, 0xD18D8549D140CAEA,
+ 0x4ED0FE7E9DC91335, 0xE4DBF0634473F5D2, 0x1761F93A44D5AEFE, 0x53898E4C3910DA55,
+ 0x734DE8181F6EC39A, 0x2680B122BAA28D97, 0x298AF231C85BAFAB, 0x7983EED3740847D5,
+ 0x66C1A2A1A60CD889, 0x9E17E49642A3E4C1, 0xEDB454E7BADC0805, 0x50B704CAB602C329,
+ 0x4CC317FB9CDDD023, 0x66B4835D9EAFEA22, 0x219B97E26FFC81BD, 0x261E4E4C0A333A9D,
+ 0x1FE2CCA76517DB90, 0xD7504DFA8816EDBB, 0xB9571FA04DC089C8, 0x1DDC0325259B27DE,
+ 0xCF3F4688801EB9AA, 0xF4F5D05C10CAB243, 0x38B6525C21A42B0E, 0x36F60E2BA4FA6800,
+ 0xEB3593803173E0CE, 0x9C4CD6257C5A3603, 0xAF0C317D32ADAA8A, 0x258E5A80C7204C4B,
+ 0x8B889D624D44885D, 0xF4D14597E660F855, 0xD4347F66EC8941C3, 0xE699ED85B0DFB40D,
+ 0x2472F6207C2D0484, 0xC2A1E7B5B459AEB5, 0xAB4F6451CC1D45EC, 0x63767572AE3D6174,
+ 0xA59E0BD101731A28, 0x116D0016CB948F09, 0x2CF9C8CA052F6E9F, 0x0B090A7560A968E3,
+ 0xABEEDDB2DDE06FF1, 0x58EFC10B06A2068D, 0xC6E57A78FBD986E0, 0x2EAB8CA63CE802D7,
+ 0x14A195640116F336, 0x7C0828DD624EC390, 0xD74BBE77E6116AC7, 0x804456AF10F5FB53,
+ 0xEBE9EA2ADF4321C7, 0x03219A39EE587A30, 0x49787FEF17AF9924, 0xA1E9300CD8520548,
+ 0x5B45E522E4B1B4EF, 0xB49C3B3995091A36, 0xD4490AD526F14431, 0x12A8F216AF9418C2,
+ 0x001F837CC7350524, 0x1877B51E57A764D5, 0xA2853B80F17F58EE, 0x993E1DE72D36D310,
+ 0xB3598080CE64A656, 0x252F59CF0D9F04BB, 0xD23C8E176D113600, 0x1BDA0492E7E4586E,
+ 0x21E0BD5026C619BF, 0x3B097ADAF088F94E, 0x8D14DEDB30BE846E, 0xF95CFFA23AF5F6F4,
+ 0x3871700761B3F743, 0xCA672B91E9E4FA16, 0x64C8E531BFF53B55, 0x241260ED4AD1E87D,
+ 0x106C09B972D2E822, 0x7FBA195410E5CA30, 0x7884D9BC6CB569D8, 0x0647DFEDCD894A29,
+ 0x63573FF03E224774, 0x4FC8E9560F91B123, 0x1DB956E450275779, 0xB8D91274B9E9D4FB,
+ 0xA2EBEE47E2FBFCE1, 0xD9F1F30CCD97FB09, 0xEFED53D75FD64E6B, 0x2E6D02C36017F67F,
+ 0xA9AA4D20DB084E9B, 0xB64BE8D8B25396C1, 0x70CB6AF7C2D5BCF0, 0x98F076A4F7A2322E,
+ 0xBF84470805E69B5F, 0x94C3251F06F90CF3, 0x3E003E616A6591E9, 0xB925A6CD0421AFF3,
+ 0x61BDD1307C66E300, 0xBF8D5108E27E0D48, 0x240AB57A8B888B20, 0xFC87614BAF287E07,
+ 0xEF02CDD06FFDB432, 0xA1082C0466DF6C0A, 0x8215E577001332C8, 0xD39BB9C3A48DB6CF,
+ 0x2738259634305C14, 0x61CF4F94C97DF93D, 0x1B6BACA2AE4E125B, 0x758F450C88572E0B,
+ 0x959F587D507A8359, 0xB063E962E045F54D, 0x60E8ED72C0DFF5D1, 0x7B64978555326F9F,
+ 0xFD080D236DA814BA, 0x8C90FD9B083F4558, 0x106F72FE81E2C590, 0x7976033A39F7D952,
+ 0xA4EC0132764CA04B, 0x733EA705FAE4FA77, 0xB4D8F77BC3E56167, 0x9E21F4F903B33FD9,
+ 0x9D765E419FB69F6D, 0xD30C088BA61EA5EF, 0x5D94337FBFAF7F5B, 0x1A4E4822EB4D7A59,
+ 0x6FFE73E81B637FB3, 0xDDF957BC36D8B9CA, 0x64D0E29EEA8838B3, 0x08DD9BDFD96B9F63,
+ 0x087E79E5A57D1D13, 0xE328E230E3E2B3FB, 0x1C2559E30F0946BE, 0x720BF5F26F4D2EAA,
+ 0xB0774D261CC609DB, 0x443F64EC5A371195, 0x4112CF68649A260E, 0xD813F2FAB7F5C5CA,
+ 0x660D3257380841EE, 0x59AC2C7873F910A3, 0xE846963877671A17, 0x93B633ABFA3469F8,
+ 0xC0C0F5A60EF4CDCF, 0xCAF21ECD4377B28C, 0x57277707199B8175, 0x506C11B9D90E8B1D,
+ 0xD83CC2687A19255F, 0x4A29C6465A314CD1, 0xED2DF21216235097, 0xB5635C95FF7296E2,
+ 0x22AF003AB672E811, 0x52E762596BF68235, 0x9AEBA33AC6ECC6B0, 0x944F6DE09134DFB6,
+ 0x6C47BEC883A7DE39, 0x6AD047C430A12104, 0xA5B1CFDBA0AB4067, 0x7C45D833AFF07862,
+ 0x5092EF950A16DA0B, 0x9338E69C052B8E7B, 0x455A4B4CFE30E3F5, 0x6B02E63195AD0CF8,
+ 0x6B17B224BAD6BF27, 0xD1E0CCD25BB9C169, 0xDE0C89A556B9AE70, 0x50065E535A213CF6,
+ 0x9C1169FA2777B874, 0x78EDEFD694AF1EED, 0x6DC93D9526A50E68, 0xEE97F453F06791ED,
+ 0x32AB0EDB696703D3, 0x3A6853C7E70757A7, 0x31865CED6120F37D, 0x67FEF95D92607890,
+ 0x1F2B1D1F15F6DC9C, 0xB69E38A8965C6B65, 0xAA9119FF184CCCF4, 0xF43C732873F24C13,
+ 0xFB4A3D794A9A80D2, 0x3550C2321FD6109C, 0x371F77E76BB8417E, 0x6BFA9AAE5EC05779,
+ 0xCD04F3FF001A4778, 0xE3273522064480CA, 0x9F91508BFFCFC14A, 0x049A7F41061A9E60,
+ 0xFCB6BE43A9F2FE9B, 0x08DE8A1C7797DA9B, 0x8F9887E6078735A1, 0xB5B4071DBFC73A66,
+ 0x230E343DFBA08D33, 0x43ED7F5A0FAE657D, 0x3A88A0FBBCB05C63, 0x21874B8B4D2DBC4F,
+ 0x1BDEA12E35F6A8C9, 0x53C065C6C8E63528, 0xE34A1D250E7A8D6B, 0xD6B04D3B7651DD7E,
+ 0x5E90277E7CB39E2D, 0x2C046F22062DC67D, 0xB10BB459132D0A26, 0x3FA9DDFB67E2F199,
+ 0x0E09B88E1914F7AF, 0x10E8B35AF3EEAB37, 0x9EEDECA8E272B933, 0xD4C718BC4AE8AE5F,
+ 0x81536D601170FC20, 0x91B534F885818A06, 0xEC8177F83F900978, 0x190E714FADA5156E,
+ 0xB592BF39B0364963, 0x89C350C893AE7DC1, 0xAC042E70F8B383F2, 0xB49B52E587A1EE60,
+ 0xFB152FE3FF26DA89, 0x3E666E6F69AE2C15, 0x3B544EBE544C19F9, 0xE805A1E290CF2456,
+ 0x24B33C9D7ED25117, 0xE74733427B72F0C1, 0x0A804D18B7097475, 0x57E3306D881EDB4F,
+ 0x4AE7D6A36EB5DBCB, 0x2D8D5432157064C8, 0xD1E649DE1E7F268B, 0x8A328A1CEDFE552C,
+ 0x07A3AEC79624C7DA, 0x84547DDC3E203C94, 0x990A98FD5071D263, 0x1A4FF12616EEFC89,
+ 0xF6F7FD1431714200, 0x30C05B1BA332F41C, 0x8D2636B81555A786, 0x46C9FEB55D120902,
+ 0xCCEC0A73B49C9921, 0x4E9D2827355FC492, 0x19EBB029435DCB0F, 0x4659D2B743848A2C,
+ 0x963EF2C96B33BE31, 0x74F85198B05A2E7D, 0x5A0F544DD2B1FB18, 0x03727073C2E134B1,
+ 0xC7F6AA2DE59AEA61, 0x352787BAA0D7C22F, 0x9853EAB63B5E0B35, 0xABBDCDD7ED5C0860,
+ 0xCF05DAF5AC8D77B0, 0x49CAD48CEBF4A71E, 0x7A4C10EC2158C4A6, 0xD9E92AA246BF719E,
+ 0x13AE978D09FE5557, 0x730499AF921549FF, 0x4E4B705B92903BA4, 0xFF577222C14F0A3A,
+ 0x55B6344CF97AAFAE, 0xB862225B055B6960, 0xCAC09AFBDDD2CDB4, 0xDAF8E9829FE96B5F,
+ 0xB5FDFC5D3132C498, 0x310CB380DB6F7503, 0xE87FBB46217A360E, 0x2102AE466EBB1148,
+ 0xF8549E1A3AA5E00D, 0x07A69AFDCC42261A, 0xC4C118BFE78FEAAE, 0xF9F4892ED96BD438,
+ 0x1AF3DBE25D8F45DA, 0xF5B4B0B0D2DEEEB4, 0x962ACEEFA82E1C84, 0x046E3ECAAF453CE9,
+ 0xF05D129681949A4C, 0x964781CE734B3C84, 0x9C2ED44081CE5FBD, 0x522E23F3925E319E,
+ 0x177E00F9FC32F791, 0x2BC60A63A6F3B3F2, 0x222BBFAE61725606, 0x486289DDCC3D6780,
+ 0x7DC7785B8EFDFC80, 0x8AF38731C02BA980, 0x1FAB64EA29A2DDF7, 0xE4D9429322CD065A,
+ 0x9DA058C67844F20C, 0x24C0E332B70019B0, 0x233003B5A6CFE6AD, 0xD586BD01C5C217F6,
+ 0x5E5637885F29BC2B, 0x7EBA726D8C94094B, 0x0A56A5F0BFE39272, 0xD79476A84EE20D06,
+ 0x9E4C1269BAA4BF37, 0x17EFEE45B0DEE640, 0x1D95B0A5FCF90BC6, 0x93CBE0B699C2585D,
+ 0x65FA4F227A2B6D79, 0xD5F9E858292504D5, 0xC2B5A03F71471A6F, 0x59300222B4561E00,
+ 0xCE2F8642CA0712DC, 0x7CA9723FBB2E8988, 0x2785338347F2BA08, 0xC61BB3A141E50E8C,
+ 0x150F361DAB9DEC26, 0x9F6A419D382595F4, 0x64A53DC924FE7AC9, 0x142DE49FFF7A7C3D,
+ 0x0C335248857FA9E7, 0x0A9C32D5EAE45305, 0xE6C42178C4BBB92E, 0x71F1CE2490D20B07,
+ 0xF1BCC3D275AFE51A, 0xE728E8C83C334074, 0x96FBF83A12884624, 0x81A1549FD6573DA5,
+ 0x5FA7867CAF35E149, 0x56986E2EF3ED091B, 0x917F1DD5F8886C61, 0xD20D8C88C8FFE65F,
+ 0x31D71DCE64B2C310, 0xF165B587DF898190, 0xA57E6339DD2CF3A0, 0x1EF6E6DBB1961EC9,
+ 0x70CC73D90BC26E24, 0xE21A6B35DF0C3AD7, 0x003A93D8B2806962, 0x1C99DED33CB890A1,
+ 0xCF3145DE0ADD4289, 0xD0E4427A5514FB72, 0x77C621CC9FB3A483, 0x67A34DAC4356550B,
+ 0xF8D626AAAF278509};
static constexpr std::array castlingKey = []() constexpr {
auto generateCastlingKey = [](int index) constexpr -> U64 {
@@ -1686,8 +1835,10 @@ class Zobrist {
U64 key = 0;
- for (int i = 0; i < RANDOM_COUNT; ++i) {
- if (index & (1 << i)) {
+ for (int i = 0; i < RANDOM_COUNT; ++i)
+ {
+ if (index & (1 << i))
+ {
key ^= RANDOM_ARRAY[RANDOM_OFFSET + i];
}
}
@@ -1697,7 +1848,8 @@ class Zobrist {
std::array arr{};
- for (int i = 0; i < 16; ++i) arr[i] = generateCastlingKey(i);
+ for (int i = 0; i < 16; ++i)
+ arr[i] = generateCastlingKey(i);
return arr;
}();
@@ -1736,25 +1888,29 @@ namespace chess {
namespace detail {
inline std::optional parseStringViewToInt(std::string_view sv) {
- if (sv.empty()) return std::nullopt;
+ if (sv.empty())
+ return std::nullopt;
std::string_view parsed_sv = sv;
- if (parsed_sv.back() == ';') parsed_sv.remove_suffix(1);
+ if (parsed_sv.back() == ';')
+ parsed_sv.remove_suffix(1);
- if (parsed_sv.empty()) return std::nullopt;
+ if (parsed_sv.empty())
+ return std::nullopt;
#ifdef CHESS_USE_CHARCONV
- int result;
- const char *begin = parsed_sv.data();
- const char *end = begin + parsed_sv.size();
+ int result;
+ const char* begin = parsed_sv.data();
+ const char* end = begin + parsed_sv.size();
auto [ptr, ec] = std::from_chars(begin, end, result);
- if (ec == std::errc() && ptr == end) {
+ if (ec == std::errc() && ptr == end)
+ {
return result;
}
#else
- std::string str(parsed_sv);
+ std::string str(parsed_sv);
std::stringstream ss(str);
ss.exceptions(std::ios::goodbit);
@@ -1762,7 +1918,8 @@ inline std::optional parseStringViewToInt(std::string_view sv) {
int value;
ss >> value;
- if (!ss.fail() && (ss.eof() || (ss >> std::ws).eof())) {
+ if (!ss.fail() && (ss.eof() || (ss >> std::ws).eof()))
+ {
return value;
}
#endif
@@ -1771,7 +1928,12 @@ inline std::optional parseStringViewToInt(std::string_view sv) {
}
} // namespace detail
-enum class GameResult { WIN, LOSE, DRAW, NONE };
+enum class GameResult {
+ WIN,
+ LOSE,
+ DRAW,
+ NONE
+};
enum class GameResultReason {
CHECKMATE,
@@ -1782,7 +1944,11 @@ enum class GameResultReason {
NONE
};
-enum class CheckType { NO_CHECK, DIRECT_CHECK, DISCOVERY_CHECK };
+enum class CheckType {
+ NO_CHECK,
+ DIRECT_CHECK,
+ DISCOVERY_CHECK
+};
// A compact representation of the board in 24 bytes,
// does not include the half-move clock or full move number.
@@ -1794,13 +1960,18 @@ class Board {
public:
class CastlingRights {
public:
- enum class Side : std::uint8_t { KING_SIDE, QUEEN_SIDE };
+ enum class Side : std::uint8_t {
+ KING_SIDE,
+ QUEEN_SIDE
+ };
constexpr void setCastlingRight(Color color, Side castle, File rook_file) {
rooks[color][static_cast(castle)] = rook_file;
}
- constexpr void clear() { rooks[0][0] = rooks[0][1] = rooks[1][0] = rooks[1][1] = File::NO_FILE; }
+ constexpr void clear() {
+ rooks[0][0] = rooks[0][1] = rooks[1][0] = rooks[1][1] = File::NO_FILE;
+ }
constexpr int clear(Color color, Side castle) {
rooks[color][static_cast(castle)] = File::NO_FILE;
@@ -1813,18 +1984,22 @@ class Board {
return rooks[color][static_cast(castle)] != File::NO_FILE;
}
- constexpr bool has(Color color) const { return has(color, Side::KING_SIDE) || has(color, Side::QUEEN_SIDE); }
+ constexpr bool has(Color color) const {
+ return has(color, Side::KING_SIDE) || has(color, Side::QUEEN_SIDE);
+ }
- constexpr File getRookFile(Color color, Side castle) const { return rooks[color][static_cast(castle)]; }
+ constexpr File getRookFile(Color color, Side castle) const {
+ return rooks[color][static_cast(castle)];
+ }
constexpr int hashIndex() const {
- return has(Color::WHITE, Side::KING_SIDE) + 2 * has(Color::WHITE, Side::QUEEN_SIDE) +
- 4 * has(Color::BLACK, Side::KING_SIDE) + 8 * has(Color::BLACK, Side::QUEEN_SIDE);
+ return has(Color::WHITE, Side::KING_SIDE) + 2 * has(Color::WHITE, Side::QUEEN_SIDE)
+ + 4 * has(Color::BLACK, Side::KING_SIDE) + 8 * has(Color::BLACK, Side::QUEEN_SIDE);
}
constexpr bool isEmpty() const { return !has(Color::WHITE) && !has(Color::BLACK); }
- template
+ template
static constexpr Side closestSide(T sq, T pred) {
return sq > pred ? Side::KING_SIDE : Side::QUEEN_SIDE;
}
@@ -1835,22 +2010,27 @@ class Board {
private:
struct State {
- U64 hash;
+ U64 hash;
CastlingRights castling;
- Square enpassant;
- std::uint8_t half_moves;
- Piece captured_piece;
-
- State(const U64 &hash, const CastlingRights &castling, const Square &enpassant, const std::uint8_t &half_moves,
- const Piece &captured_piece)
- : hash(hash),
- castling(castling),
- enpassant(enpassant),
- half_moves(half_moves),
- captured_piece(captured_piece) {}
+ Square enpassant;
+ std::uint8_t half_moves;
+ Piece captured_piece;
+
+ State(const U64& hash,
+ const CastlingRights& castling,
+ const Square& enpassant,
+ const std::uint8_t& half_moves,
+ const Piece& captured_piece) :
+ hash(hash),
+ castling(castling),
+ enpassant(enpassant),
+ half_moves(half_moves),
+ captured_piece(captured_piece) {}
};
- enum class PrivateCtor { CREATE };
+ enum class PrivateCtor {
+ CREATE
+ };
// private constructor to avoid initialization
Board(PrivateCtor) {}
@@ -1885,36 +2065,47 @@ class Board {
bool setEpd(const std::string_view epd) {
auto parts = utils::splitString(epd, ' ');
- if (parts.size() < 4) return false;
+ if (parts.size() < 4)
+ return false;
int hm = 0;
int fm = 1;
- if (auto it = std::find(parts.begin(), parts.end(), "hmvc"); it != parts.end()) {
- if (std::distance(it, parts.end()) > 1) {
+ if (auto it = std::find(parts.begin(), parts.end(), "hmvc"); it != parts.end())
+ {
+ if (std::distance(it, parts.end()) > 1)
+ {
auto num = *(it + 1);
auto parsed = detail::parseStringViewToInt(num);
- if (parsed) hm = *parsed;
- } else {
+ if (parsed)
+ hm = *parsed;
+ }
+ else
+ {
return false;
}
}
- if (auto it = std::find(parts.begin(), parts.end(), "fmvn"); it != parts.end()) {
- if (std::distance(it, parts.end()) > 1) {
+ if (auto it = std::find(parts.begin(), parts.end(), "fmvn"); it != parts.end())
+ {
+ if (std::distance(it, parts.end()) > 1)
+ {
auto num = *(it + 1);
auto parsed = detail::parseStringViewToInt(num);
if (parsed && *parsed > 0)
fm = *parsed;
else
return false;
- } else {
+ }
+ else
+ {
return false;
}
}
- auto fen = std::string(parts[0]) + " " + std::string(parts[1]) + " " + std::string(parts[2]) + " " +
- std::string(parts[3]) + " " + std::to_string(hm) + " " + std::to_string(fm);
+ auto fen = std::string(parts[0]) + " " + std::string(parts[1]) + " " + std::string(parts[2])
+ + " " + std::string(parts[3]) + " " + std::to_string(hm) + " "
+ + std::to_string(fm);
return setFen(fen);
}
@@ -1929,26 +2120,32 @@ class Board {
ss.reserve(100);
// Loop through the ranks of the board in reverse order
- for (int rank = 7; rank >= 0; rank--) {
+ for (int rank = 7; rank >= 0; rank--)
+ {
std::uint32_t free_space = 0;
// Loop through the files of the board
- for (int file = 0; file < 8; file++) {
+ for (int file = 0; file < 8; file++)
+ {
// Calculate the square index
const int sq = rank * 8 + file;
// If there is a piece at the current square
- if (Piece piece = at(Square(sq)); piece != Piece::NONE) {
+ if (Piece piece = at(Square(sq)); piece != Piece::NONE)
+ {
// If there were any empty squares before this piece,
// append the number of empty squares to the FEN string
- if (free_space) {
+ if (free_space)
+ {
ss += std::to_string(free_space);
free_space = 0;
}
// Append the character representing the piece to the FEN string
ss += static_cast(piece);
- } else {
+ }
+ else
+ {
// If there is no piece at the current square, increment the
// counter for the number of empty squares
free_space++;
@@ -1957,7 +2154,8 @@ class Board {
// If there are any empty squares at the end of the rank,
// append the number of empty squares to the FEN string
- if (free_space != 0) {
+ if (free_space != 0)
+ {
ss += std::to_string(free_space);
}
@@ -1973,7 +2171,8 @@ class Board {
// whether castling is allowed for each player
if (cr_.isEmpty())
ss += " -";
- else {
+ else
+ {
ss += ' ';
ss += getCastleString();
}
@@ -1982,12 +2181,14 @@ class Board {
// and the half-move clock and full move number to the FEN string
if (ep_sq_ == Square::NO_SQ)
ss += " -";
- else {
+ else
+ {
ss += ' ';
ss += static_cast(ep_sq_);
}
- if (move_counters) {
+ if (move_counters)
+ {
ss += ' ';
ss += std::to_string(halfMoveClock());
ss += ' ';
@@ -2019,7 +2220,7 @@ class Board {
* @tparam EXACT
* @param move
*/
- template
+ template
void makeMove(const Move move) {
const auto capture = at(move.to()) != Piece::NONE && move.typeOf() != Move::CASTLING;
const auto captured = at(move.to());
@@ -2033,53 +2234,66 @@ class Board {
hfm_++;
plies_++;
- if (ep_sq_ != Square::NO_SQ) key_ ^= Zobrist::enpassant(ep_sq_.file());
+ if (ep_sq_ != Square::NO_SQ)
+ key_ ^= Zobrist::enpassant(ep_sq_.file());
ep_sq_ = Square::NO_SQ;
- if (capture) {
+ if (capture)
+ {
removePiece(captured, move.to());
hfm_ = 0;
key_ ^= Zobrist::piece(captured, move.to());
// remove castling rights if rook is captured
- if (captured.type() == PieceType::ROOK && Rank::back_rank(move.to().rank(), ~stm_)) {
+ if (captured.type() == PieceType::ROOK && Rank::back_rank(move.to().rank(), ~stm_))
+ {
const auto king_sq = kingSq(~stm_);
const auto file = CastlingRights::closestSide(move.to(), king_sq);
- if (cr_.getRookFile(~stm_, file) == move.to().file()) {
+ if (cr_.getRookFile(~stm_, file) == move.to().file())
+ {
key_ ^= Zobrist::castlingIndex(cr_.clear(~stm_, file));
}
}
}
// remove castling rights if king moves
- if (pt == PieceType::KING && cr_.has(stm_)) {
+ if (pt == PieceType::KING && cr_.has(stm_))
+ {
key_ ^= Zobrist::castling(cr_.hashIndex());
cr_.clear(stm_);
key_ ^= Zobrist::castling(cr_.hashIndex());
- } else if (pt == PieceType::ROOK && Square::back_rank(move.from(), stm_)) {
+ }
+ else if (pt == PieceType::ROOK && Square::back_rank(move.from(), stm_))
+ {
const auto king_sq = kingSq(stm_);
const auto file = CastlingRights::closestSide(move.from(), king_sq);
// remove castling rights if rook moves from back rank
- if (cr_.getRookFile(stm_, file) == move.from().file()) {
+ if (cr_.getRookFile(stm_, file) == move.from().file())
+ {
key_ ^= Zobrist::castlingIndex(cr_.clear(stm_, file));
}
- } else if (pt == PieceType::PAWN) {
+ }
+ else if (pt == PieceType::PAWN)
+ {
hfm_ = 0;
// double push
- if (Square::value_distance(move.to(), move.from()) == 16) {
+ if (Square::value_distance(move.to(), move.from()) == 16)
+ {
// imaginary attacks from the ep square from the pawn which moved
Bitboard ep_mask = attacks::pawn(stm_, move.to().ep_square());
// add enpassant hash if enemy pawns are attacking the square
- if (static_cast(ep_mask & pieces(PieceType::PAWN, ~stm_))) {
+ if (static_cast(ep_mask & pieces(PieceType::PAWN, ~stm_)))
+ {
int found = -1;
// check if the enemy can legally capture the pawn on the next move
- if constexpr (EXACT) {
+ if constexpr (EXACT)
+ {
const auto piece = at(move.from());
found = 0;
@@ -2091,13 +2305,19 @@ class Board {
bool valid;
- if (stm_ == Color::WHITE) {
- valid = movegen::isEpSquareValid(*this, move.to().ep_square());
- } else {
- valid = movegen::isEpSquareValid(*this, move.to().ep_square());
+ if (stm_ == Color::WHITE)
+ {
+ valid =
+ movegen::isEpSquareValid(*this, move.to().ep_square());
+ }
+ else
+ {
+ valid =
+ movegen::isEpSquareValid(*this, move.to().ep_square());
}
- if (valid) found = 1;
+ if (valid)
+ found = 1;
// undo
stm_ = ~stm_;
@@ -2106,7 +2326,8 @@ class Board {
placePieceInternal(piece, move.from());
}
- if (found != 0) {
+ if (found != 0)
+ {
assert(at(move.to().ep_square()) == Piece::NONE);
ep_sq_ = move.to().ep_square();
key_ ^= Zobrist::enpassant(move.to().ep_square().file());
@@ -2115,7 +2336,8 @@ class Board {
}
}
- if (move.typeOf() == Move::CASTLING) {
+ if (move.typeOf() == Move::CASTLING)
+ {
assert(at(move.from()) == PieceType::KING);
assert(at(move.to()) == PieceType::ROOK);
@@ -2137,7 +2359,9 @@ class Board {
key_ ^= Zobrist::piece(king, move.from()) ^ Zobrist::piece(king, kingTo);
key_ ^= Zobrist::piece(rook, move.to()) ^ Zobrist::piece(rook, rookTo);
- } else if (move.typeOf() == Move::PROMOTION) {
+ }
+ else if (move.typeOf() == Move::PROMOTION)
+ {
const auto piece_pawn = Piece(PieceType::PAWN, stm_);
const auto piece_prom = Piece(move.promotionType(), stm_);
@@ -2145,7 +2369,9 @@ class Board {
placePiece(piece_prom, move.to());
key_ ^= Zobrist::piece(piece_pawn, move.from()) ^ Zobrist::piece(piece_prom, move.to());
- } else {
+ }
+ else
+ {
assert(at(move.from()) != Piece::NONE);
assert(at(move.to()) == Piece::NONE);
@@ -2157,7 +2383,8 @@ class Board {
key_ ^= Zobrist::piece(piece, move.from()) ^ Zobrist::piece(piece, move.to());
}
- if (move.typeOf() == Move::ENPASSANT) {
+ if (move.typeOf() == Move::ENPASSANT)
+ {
assert(at(move.to().ep_square()) == PieceType::PAWN);
const auto piece = Piece(PieceType::PAWN, ~stm_);
@@ -2172,7 +2399,7 @@ class Board {
}
void unmakeMove(const Move move) {
- const auto &prev = prev_states_.back();
+ const auto& prev = prev_states_.back();
ep_sq_ = prev.enpassant;
cr_ = prev.castling;
@@ -2180,10 +2407,13 @@ class Board {
stm_ = ~stm_;
plies_--;
- if (move.typeOf() == Move::CASTLING) {
- const bool king_side = move.to() > move.from();
- const auto rook_from_sq = Square(king_side ? File::FILE_F : File::FILE_D, move.from().rank());
- const auto king_to_sq = Square(king_side ? File::FILE_G : File::FILE_C, move.from().rank());
+ if (move.typeOf() == Move::CASTLING)
+ {
+ const bool king_side = move.to() > move.from();
+ const auto rook_from_sq =
+ Square(king_side ? File::FILE_F : File::FILE_D, move.from().rank());
+ const auto king_to_sq =
+ Square(king_side ? File::FILE_G : File::FILE_C, move.from().rank());
assert(at(rook_from_sq) == PieceType::ROOK);
assert(at(king_to_sq) == PieceType::KING);
@@ -2199,8 +2429,9 @@ class Board {
placePiece(king, move.from());
placePiece(rook, move.to());
-
- } else if (move.typeOf() == Move::PROMOTION) {
+ }
+ else if (move.typeOf() == Move::PROMOTION)
+ {
const auto pawn = Piece(PieceType::PAWN, stm_);
const auto piece = at(move.to());
@@ -2212,12 +2443,14 @@ class Board {
removePiece(piece, move.to());
placePiece(pawn, move.from());
- if (prev.captured_piece != Piece::NONE) {
+ if (prev.captured_piece != Piece::NONE)
+ {
assert(at(move.to()) == Piece::NONE);
placePiece(prev.captured_piece, move.to());
}
-
- } else {
+ }
+ else
+ {
assert(at(move.to()) != Piece::NONE);
assert(at(move.from()) == Piece::NONE);
@@ -2226,14 +2459,17 @@ class Board {
removePiece(piece, move.to());
placePiece(piece, move.from());
- if (move.typeOf() == Move::ENPASSANT) {
+ if (move.typeOf() == Move::ENPASSANT)
+ {
const auto pawn = Piece(PieceType::PAWN, ~stm_);
const auto pawnTo = static_cast(ep_sq_ ^ 8);
assert(at(pawnTo) == Piece::NONE);
placePiece(pawn, pawnTo);
- } else if (prev.captured_piece != Piece::NONE) {
+ }
+ else if (prev.captured_piece != Piece::NONE)
+ {
assert(at(move.to()) == Piece::NONE);
placePiece(prev.captured_piece, move.to());
@@ -2251,7 +2487,8 @@ class Board {
prev_states_.emplace_back(key_, cr_, ep_sq_, hfm_, Piece::NONE);
key_ ^= Zobrist::sideToMove();
- if (ep_sq_ != Square::NO_SQ) key_ ^= Zobrist::enpassant(ep_sq_.file());
+ if (ep_sq_ != Square::NO_SQ)
+ key_ ^= Zobrist::enpassant(ep_sq_.file());
ep_sq_ = Square::NO_SQ;
stm_ = ~stm_;
@@ -2263,7 +2500,7 @@ class Board {
* @brief Unmake a null move. (Switches the side to move)
*/
void unmakeNullMove() {
- const auto &prev = prev_states_.back();
+ const auto& prev = prev_states_.back();
ep_sq_ = prev.enpassant;
cr_ = prev.castling;
@@ -2331,7 +2568,8 @@ class Board {
*/
[[nodiscard]] Bitboard pieces(PieceType type) const noexcept { return pieces_bb_[type]; }
- template && ...)>>
+ template && ...)>>
[[nodiscard]] Bitboard pieces(Pieces... pieces) const noexcept {
return (pieces_bb_[static_cast(pieces)] | ...);
}
@@ -2342,13 +2580,16 @@ class Board {
* @param sq
* @return
*/
- template
+ template
[[nodiscard]] T at(Square sq) const noexcept {
assert(sq.is_valid());
- if constexpr (std::is_same_v) {
+ if constexpr (std::is_same_v)
+ {
return board_[sq.index()].type();
- } else {
+ }
+ else
+ {
return board_[sq.index()];
}
}
@@ -2359,23 +2600,25 @@ class Board {
* @return
*/
bool isCapture(const Move move) const noexcept {
- return (at(move.to()) != Piece::NONE && move.typeOf() != Move::CASTLING) || move.typeOf() == Move::ENPASSANT;
+ return (at(move.to()) != Piece::NONE && move.typeOf() != Move::CASTLING)
+ || move.typeOf() == Move::ENPASSANT;
}
/**
* @brief Get the current zobrist hash key of the board
* @return
*/
- [[nodiscard]] U64 hash() const noexcept { return key_; }
- [[nodiscard]] Color sideToMove() const noexcept { return stm_; }
- [[nodiscard]] Square enpassantSq() const noexcept { return ep_sq_; }
+ [[nodiscard]] U64 hash() const noexcept { return key_; }
+ [[nodiscard]] Color sideToMove() const noexcept { return stm_; }
+ [[nodiscard]] Square enpassantSq() const noexcept { return ep_sq_; }
[[nodiscard]] CastlingRights castlingRights() const noexcept { return cr_; }
- [[nodiscard]] std::uint32_t halfMoveClock() const noexcept { return hfm_; }
- [[nodiscard]] std::uint32_t fullMoveNumber() const noexcept { return 1 + plies_ / 2; }
+ [[nodiscard]] std::uint32_t halfMoveClock() const noexcept { return hfm_; }
+ [[nodiscard]] std::uint32_t fullMoveNumber() const noexcept { return 1 + plies_ / 2; }
void set960(bool is960) {
chess960_ = is960;
- if (!original_fen_.empty()) setFen(original_fen_);
+ if (!original_fen_.empty())
+ setFen(original_fen_);
}
/**
@@ -2389,27 +2632,35 @@ class Board {
* @return
*/
[[nodiscard]] std::string getCastleString() const {
- static const auto get_file = [](const CastlingRights &cr, Color c, CastlingRights::Side side) {
+ static const auto get_file = [](const CastlingRights& cr, Color c,
+ CastlingRights::Side side) {
auto file = static_cast(cr.getRookFile(c, side));
return c == Color::WHITE ? std::toupper(file[0]) : file[0];
};
- if (chess960_) {
+ if (chess960_)
+ {
std::string ss;
for (auto color : {Color::WHITE, Color::BLACK})
- for (auto side : {CastlingRights::Side::KING_SIDE, CastlingRights::Side::QUEEN_SIDE})
- if (cr_.has(color, side)) ss += get_file(cr_, color, side);
+ for (auto side :
+ {CastlingRights::Side::KING_SIDE, CastlingRights::Side::QUEEN_SIDE})
+ if (cr_.has(color, side))
+ ss += get_file(cr_, color, side);
return ss;
}
std::string ss;
- if (cr_.has(Color::WHITE, CastlingRights::Side::KING_SIDE)) ss += 'K';
- if (cr_.has(Color::WHITE, CastlingRights::Side::QUEEN_SIDE)) ss += 'Q';
- if (cr_.has(Color::BLACK, CastlingRights::Side::KING_SIDE)) ss += 'k';
- if (cr_.has(Color::BLACK, CastlingRights::Side::QUEEN_SIDE)) ss += 'q';
+ if (cr_.has(Color::WHITE, CastlingRights::Side::KING_SIDE))
+ ss += 'K';
+ if (cr_.has(Color::WHITE, CastlingRights::Side::QUEEN_SIDE))
+ ss += 'Q';
+ if (cr_.has(Color::BLACK, CastlingRights::Side::KING_SIDE))
+ ss += 'k';
+ if (cr_.has(Color::BLACK, CastlingRights::Side::QUEEN_SIDE))
+ ss += 'q';
return ss;
}
@@ -2428,9 +2679,12 @@ class Board {
// be across half-moves.
const auto size = static_cast(prev_states_.size());
- for (int i = size - 2; i >= 0 && i >= size - hfm_ - 1; i -= 2) {
- if (prev_states_[i].hash == key_) c++;
- if (c == count) return true;
+ for (int i = size - 2; i >= 0 && i >= size - hfm_ - 1; i -= 2)
+ {
+ if (prev_states_[i].hash == key_)
+ c++;
+ if (c == count)
+ return true;
}
return false;
@@ -2454,7 +2708,8 @@ class Board {
Movelist movelist;
movegen::legalmoves(movelist, *this);
- if (movelist.empty() && inCheck()) {
+ if (movelist.empty() && inCheck())
+ {
return {GameResultReason::CHECKMATE, GameResult::LOSE};
}
@@ -2469,29 +2724,39 @@ class Board {
const auto count = occ().count();
// only kings, draw
- if (count == 2) return true;
+ if (count == 2)
+ return true;
// only bishop + knight, cant mate
- if (count == 3) {
- if (pieces(PieceType::BISHOP, Color::WHITE) || pieces(PieceType::BISHOP, Color::BLACK)) return true;
- if (pieces(PieceType::KNIGHT, Color::WHITE) || pieces(PieceType::KNIGHT, Color::BLACK)) return true;
+ if (count == 3)
+ {
+ if (pieces(PieceType::BISHOP, Color::WHITE) || pieces(PieceType::BISHOP, Color::BLACK))
+ return true;
+ if (pieces(PieceType::KNIGHT, Color::WHITE) || pieces(PieceType::KNIGHT, Color::BLACK))
+ return true;
}
// same colored bishops, cant mate
- if (count == 4) {
- if (pieces(PieceType::BISHOP, Color::WHITE) && pieces(PieceType::BISHOP, Color::BLACK) &&
- Square::same_color(pieces(PieceType::BISHOP, Color::WHITE).lsb(),
- pieces(PieceType::BISHOP, Color::BLACK).lsb()))
+ if (count == 4)
+ {
+ if (pieces(PieceType::BISHOP, Color::WHITE) && pieces(PieceType::BISHOP, Color::BLACK)
+ && Square::same_color(pieces(PieceType::BISHOP, Color::WHITE).lsb(),
+ pieces(PieceType::BISHOP, Color::BLACK).lsb()))
return true;
// one side with two bishops which have the same color
auto white_bishops = pieces(PieceType::BISHOP, Color::WHITE);
auto black_bishops = pieces(PieceType::BISHOP, Color::BLACK);
- if (white_bishops.count() == 2) {
- if (Square::same_color(white_bishops.lsb(), white_bishops.msb())) return true;
- } else if (black_bishops.count() == 2) {
- if (Square::same_color(black_bishops.lsb(), black_bishops.msb())) return true;
+ if (white_bishops.count() == 2)
+ {
+ if (Square::same_color(white_bishops.lsb(), white_bishops.msb()))
+ return true;
+ }
+ else if (black_bishops.count() == 2)
+ {
+ if (Square::same_color(black_bishops.lsb(), black_bishops.msb()))
+ return true;
}
}
@@ -2505,15 +2770,20 @@ class Board {
* @return
*/
[[nodiscard]] std::pair isGameOver() const noexcept {
- if (isHalfMoveDraw()) return getHalfMoveDrawType();
- if (isInsufficientMaterial()) return {GameResultReason::INSUFFICIENT_MATERIAL, GameResult::DRAW};
- if (isRepetition()) return {GameResultReason::THREEFOLD_REPETITION, GameResult::DRAW};
+ if (isHalfMoveDraw())
+ return getHalfMoveDrawType();
+ if (isInsufficientMaterial())
+ return {GameResultReason::INSUFFICIENT_MATERIAL, GameResult::DRAW};
+ if (isRepetition())
+ return {GameResultReason::THREEFOLD_REPETITION, GameResult::DRAW};
Movelist movelist;
movegen::legalmoves(movelist, *this);
- if (movelist.empty()) {
- if (inCheck()) return {GameResultReason::CHECKMATE, GameResult::LOSE};
+ if (movelist.empty())
+ {
+ if (inCheck())
+ return {GameResultReason::CHECKMATE, GameResult::LOSE};
return {GameResultReason::STALEMATE, GameResult::DRAW};
}
@@ -2528,11 +2798,17 @@ class Board {
*/
[[nodiscard]] bool isAttacked(Square square, Color color) const noexcept {
// cheap checks first
- if (attacks::pawn(~color, square) & pieces(PieceType::PAWN, color)) return true;
- if (attacks::knight(square) & pieces(PieceType::KNIGHT, color)) return true;
- if (attacks::king(square) & pieces(PieceType::KING, color)) return true;
- if (attacks::bishop(square, occ()) & pieces(PieceType::BISHOP, PieceType::QUEEN) & us(color)) return true;
- if (attacks::rook(square, occ()) & pieces(PieceType::ROOK, PieceType::QUEEN) & us(color)) return true;
+ if (attacks::pawn(~color, square) & pieces(PieceType::PAWN, color))
+ return true;
+ if (attacks::knight(square) & pieces(PieceType::KNIGHT, color))
+ return true;
+ if (attacks::king(square) & pieces(PieceType::KING, color))
+ return true;
+ if (attacks::bishop(square, occ()) & pieces(PieceType::BISHOP, PieceType::QUEEN)
+ & us(color))
+ return true;
+ if (attacks::rook(square, occ()) & pieces(PieceType::ROOK, PieceType::QUEEN) & us(color))
+ return true;
return false;
}
@@ -2543,7 +2819,7 @@ class Board {
*/
[[nodiscard]] bool inCheck() const noexcept { return isAttacked(kingSq(stm_), ~stm_); }
- [[nodiscard]] CheckType givesCheck(const Move &m) const noexcept;
+ [[nodiscard]] CheckType givesCheck(const Move& m) const noexcept;
/**
* @brief Checks if the given color has at least 1 piece thats not pawn and not king
@@ -2563,16 +2839,19 @@ class Board {
auto pieces = occ();
- while (pieces) {
+ while (pieces)
+ {
const Square sq = pieces.pop();
hash_key ^= Zobrist::piece(at(sq), sq);
}
U64 ep_hash = 0ULL;
- if (ep_sq_ != Square::NO_SQ) ep_hash ^= Zobrist::enpassant(ep_sq_.file());
+ if (ep_sq_ != Square::NO_SQ)
+ ep_hash ^= Zobrist::enpassant(ep_sq_.file());
U64 stm_hash = 0ULL;
- if (stm_ == Color::WHITE) stm_hash ^= Zobrist::sideToMove();
+ if (stm_ == Color::WHITE)
+ stm_hash ^= Zobrist::sideToMove();
U64 castling_hash = 0ULL;
castling_hash ^= Zobrist::castling(cr_.hashIndex());
@@ -2584,7 +2863,7 @@ class Board {
return castling_path[c][isKingSide];
}
- friend std::ostream &operator<<(std::ostream &os, const Board &board);
+ friend std::ostream& operator<<(std::ostream& os, const Board& board);
/**
* @brief Compresses the board into a PackedBoard.
@@ -2599,9 +2878,11 @@ class Board {
* @param board
* @return
*/
- static PackedBoard encode(const Board &board) { return encodeState(board); }
+ static PackedBoard encode(const Board& board) { return encodeState(board); }
- static PackedBoard encode(std::string_view fen, bool chess960 = false) { return encodeState(fen, chess960); }
+ static PackedBoard encode(std::string_view fen, bool chess960 = false) {
+ return encodeState(fen, chess960);
+ }
/**
* @brief Creates a Board object from a PackedBoard
@@ -2609,7 +2890,7 @@ class Board {
* @param chess960 If the board is a chess960 position, set this to true
* @return
*/
- static Board decode(const PackedBoard &compressed, bool chess960 = false) {
+ static Board decode(const PackedBoard& compressed, bool chess960 = false) {
Board board = Board(PrivateCtor::CREATE);
board.chess960_ = chess960;
decode(board, compressed);
@@ -2637,7 +2918,7 @@ class Board {
*
* We will later deduce the square of the pieces from the occupancy bitboard.
*/
- static PackedBoard encodeState(const Board &board) {
+ static PackedBoard encodeState(const Board& board) {
PackedBoard packed{};
packed[0] = board.occ().getBits() >> 56;
@@ -2652,13 +2933,15 @@ class Board {
auto offset = 8 * 2;
auto occ = board.occ();
- while (occ) {
+ while (occ)
+ {
// we now fill the packed array, since our convertedpiece only actually needs 4 bits,
// we can store 2 pieces in one byte.
- const auto sq = Square(occ.pop());
- const auto shift = (offset % 2 == 0 ? 4 : 0);
- const auto meaning = convertMeaning(board.cr_, board.sideToMove(), board.ep_sq_, sq, board.at(sq));
- const auto nibble = meaning << shift;
+ const auto sq = Square(occ.pop());
+ const auto shift = (offset % 2 == 0 ? 4 : 0);
+ const auto meaning =
+ convertMeaning(board.cr_, board.sideToMove(), board.ep_sq_, sq, board.at(sq));
+ const auto nibble = meaning << shift;
packed[offset / 2] |= nibble;
offset++;
@@ -2669,15 +2952,17 @@ class Board {
static PackedBoard encodeState(std::string_view fen, bool chess960 = false) {
// fallback to slower method
- if (chess960) {
+ if (chess960)
+ {
return encodeState(Board(fen, true));
}
PackedBoard packed{};
- while (fen[0] == ' ') fen.remove_prefix(1);
+ while (fen[0] == ' ')
+ fen.remove_prefix(1);
- const auto params = split_string_view<6>(fen);
+ const auto params = split_string_view<4>(fen);
const auto position = params[0].has_value() ? *params[0] : "";
const auto move_right = params[1].has_value() ? *params[1] : "w";
const auto castling = params[2].has_value() ? *params[2] : "-";
@@ -2688,16 +2973,22 @@ class Board {
CastlingRights cr;
- for (char i : castling) {
- if (i == '-') break;
+ for (char i : castling)
+ {
+ if (i == '-')
+ break;
const auto king_side = CastlingRights::Side::KING_SIDE;
const auto queen_side = CastlingRights::Side::QUEEN_SIDE;
- if (i == 'K') cr.setCastlingRight(Color::WHITE, king_side, File::FILE_H);
- if (i == 'Q') cr.setCastlingRight(Color::WHITE, queen_side, File::FILE_A);
- if (i == 'k') cr.setCastlingRight(Color::BLACK, king_side, File::FILE_H);
- if (i == 'q') cr.setCastlingRight(Color::BLACK, queen_side, File::FILE_A);
+ if (i == 'K')
+ cr.setCastlingRight(Color::WHITE, king_side, File::FILE_H);
+ if (i == 'Q')
+ cr.setCastlingRight(Color::WHITE, queen_side, File::FILE_A);
+ if (i == 'k')
+ cr.setCastlingRight(Color::BLACK, king_side, File::FILE_H);
+ if (i == 'q')
+ cr.setCastlingRight(Color::BLACK, queen_side, File::FILE_A);
assert(i == 'K' || i == 'Q' || i == 'k' || i == 'q');
@@ -2706,23 +2997,31 @@ class Board {
const auto parts = split_string_view<8>(position, '/');
- int offset = 8 * 2;
- int square = 0;
- Bitboard occ = 0ull;
+ int offset = 8 * 2;
+ int square = 0;
+ Bitboard occ = 0ull;
- for (auto i = parts.rbegin(); i != parts.rend(); i++) {
+ for (auto i = parts.rbegin(); i != parts.rend(); i++)
+ {
auto part = *i;
- for (char curr : *part) {
- if (isdigit(curr)) {
+ for (char curr : *part)
+ {
+ if (isdigit(curr))
+ {
square += (curr - '0');
- } else if (curr == '/') {
+ }
+ else if (curr == '/')
+ {
square++;
- } else {
+ }
+ else
+ {
const auto p = Piece(std::string_view(&curr, 1));
const auto shift = (offset % 2 == 0 ? 4 : 0);
- packed[offset / 2] |= convertMeaning(cr, stm, ep, Square(square), p) << shift;
+ packed[offset / 2] |= convertMeaning(cr, stm, ep, Square(square), p)
+ << shift;
offset++;
occ.set(square);
@@ -2743,15 +3042,16 @@ class Board {
return packed;
}
- static void decode(Board &board, const PackedBoard &compressed) {
+ static void decode(Board& board, const PackedBoard& compressed) {
Bitboard occupied = 0ull;
- for (int i = 0; i < 8; i++) {
+ for (int i = 0; i < 8; i++)
+ {
occupied |= Bitboard(compressed[i]) << (56 - i * 8);
}
- int offset = 16;
- int white_castle_idx = 0, black_castle_idx = 0;
+ int offset = 16;
+ int white_castle_idx = 0, black_castle_idx = 0;
File white_castle[2] = {File::NO_FILE, File::NO_FILE};
File black_castle[2] = {File::NO_FILE, File::NO_FILE};
@@ -2771,12 +3071,14 @@ class Board {
board.board_.fill(Piece::NONE);
// place pieces back on the board
- while (occupied) {
+ while (occupied)
+ {
const auto sq = Square(occupied.pop());
const auto nibble = compressed[offset / 2] >> (offset % 2 == 0 ? 4 : 0) & 0b1111;
const auto piece = convertPiece(nibble);
- if (piece != Piece::NONE) {
+ if (piece != Piece::NONE)
+ {
board.placePiece(piece, sq);
offset++;
@@ -2785,26 +3087,30 @@ class Board {
// Piece has a special meaning, interpret it from the raw integer
// pawn with ep square behind it
- if (nibble == 12) {
+ if (nibble == 12)
+ {
board.ep_sq_ = sq.ep_square();
// depending on the rank this is a white or black pawn
auto color = sq.rank() == Rank::RANK_4 ? Color::WHITE : Color::BLACK;
board.placePiece(Piece(PieceType::PAWN, color), sq);
}
// castling rights for white
- else if (nibble == 13) {
+ else if (nibble == 13)
+ {
assert(white_castle_idx < 2);
white_castle[white_castle_idx++] = sq.file();
board.placePiece(Piece(PieceType::ROOK, Color::WHITE), sq);
}
// castling rights for black
- else if (nibble == 14) {
+ else if (nibble == 14)
+ {
assert(black_castle_idx < 2);
black_castle[black_castle_idx++] = sq.file();
board.placePiece(Piece(PieceType::ROOK, Color::BLACK), sq);
}
// black to move
- else if (nibble == 15) {
+ else if (nibble == 15)
+ {
board.stm_ = Color::BLACK;
board.placePiece(Piece(PieceType::KING, Color::BLACK), sq);
}
@@ -2813,8 +3119,10 @@ class Board {
}
// reapply castling
- for (int i = 0; i < 2; i++) {
- if (white_castle[i] != File::NO_FILE) {
+ for (int i = 0; i < 2; i++)
+ {
+ if (white_castle[i] != File::NO_FILE)
+ {
const auto king_sq = board.kingSq(Color::WHITE);
const auto file = white_castle[i];
const auto side = CastlingRights::closestSide(file, king_sq.file());
@@ -2822,7 +3130,8 @@ class Board {
board.cr_.setCastlingRight(Color::WHITE, side, file);
}
- if (black_castle[i] != File::NO_FILE) {
+ if (black_castle[i] != File::NO_FILE)
+ {
const auto king_sq = board.kingSq(Color::BLACK);
const auto file = black_castle[i];
const auto side = CastlingRights::closestSide(file, king_sq.file());
@@ -2831,7 +3140,8 @@ class Board {
}
}
- if (board.stm_ == Color::BLACK) {
+ if (board.stm_ == Color::BLACK)
+ {
board.plies_++;
}
@@ -2843,7 +3153,8 @@ class Board {
// for pieces with a special meaning return Piece::NONE since this is otherwise not used
static Piece convertPiece(std::uint8_t piece) {
- if (piece >= 12) return Piece::NONE;
+ if (piece >= 12)
+ return Piece::NONE;
return Piece(Piece::underlying(piece));
}
@@ -2851,23 +3162,31 @@ class Board {
// 13 => any white rook with castling rights, side will be deduced from the file
// 14 => any black rook with castling rights, side will be deduced from the file
// 15 => black king and black is side to move
- static std::uint8_t convertMeaning(const CastlingRights &cr, Color stm, Square ep, Square sq, Piece piece) {
- if (piece.type() == PieceType::PAWN && ep != Square::NO_SQ) {
- if (Square(static_cast(sq.index()) ^ 8) == ep) return 12;
+ static std::uint8_t
+ convertMeaning(const CastlingRights& cr, Color stm, Square ep, Square sq, Piece piece) {
+ if (piece.type() == PieceType::PAWN && ep != Square::NO_SQ)
+ {
+ if (Square(static_cast(sq.index()) ^ 8) == ep)
+ return 12;
}
- if (piece.type() == PieceType::ROOK) {
- if (piece.color() == Color::WHITE && Square::back_rank(sq, Color::WHITE) &&
- (cr.getRookFile(Color::WHITE, CastlingRights::Side::KING_SIDE) == sq.file() ||
- cr.getRookFile(Color::WHITE, CastlingRights::Side::QUEEN_SIDE) == sq.file()))
+ if (piece.type() == PieceType::ROOK)
+ {
+ if (piece.color() == Color::WHITE && Square::back_rank(sq, Color::WHITE)
+ && (cr.getRookFile(Color::WHITE, CastlingRights::Side::KING_SIDE) == sq.file()
+ || cr.getRookFile(Color::WHITE, CastlingRights::Side::QUEEN_SIDE)
+ == sq.file()))
return 13;
- if (piece.color() == Color::BLACK && Square::back_rank(sq, Color::BLACK) &&
- (cr.getRookFile(Color::BLACK, CastlingRights::Side::KING_SIDE) == sq.file() ||
- cr.getRookFile(Color::BLACK, CastlingRights::Side::QUEEN_SIDE) == sq.file()))
+ if (piece.color() == Color::BLACK && Square::back_rank(sq, Color::BLACK)
+ && (cr.getRookFile(Color::BLACK, CastlingRights::Side::KING_SIDE) == sq.file()
+ || cr.getRookFile(Color::BLACK, CastlingRights::Side::QUEEN_SIDE)
+ == sq.file()))
return 14;
}
- if (piece.type() == PieceType::KING && piece.color() == Color::BLACK && stm == Color::BLACK) {
+ if (piece.type() == PieceType::KING && piece.color() == Color::BLACK
+ && stm == Color::BLACK)
+ {
return 15;
}
@@ -2884,14 +3203,14 @@ class Board {
std::array pieces_bb_ = {};
std::array occ_bb_ = {};
- std::array board_ = {};
+ std::array board_ = {};
- U64 key_ = 0ULL;
- CastlingRights cr_ = {};
- std::uint16_t plies_ = 0;
- Color stm_ = Color::WHITE;
- Square ep_sq_ = Square::NO_SQ;
- std::uint8_t hfm_ = 0;
+ U64 key_ = 0ULL;
+ CastlingRights cr_ = {};
+ std::uint16_t plies_ = 0;
+ Color stm_ = Color::WHITE;
+ Square ep_sq_ = Square::NO_SQ;
+ std::uint8_t hfm_ = 0;
bool chess960_ = false;
@@ -2930,15 +3249,17 @@ class Board {
board_[index] = piece;
}
- template
+ template
bool setFenInternal(std::string_view fen) {
original_fen_ = fen;
reset();
- while (!fen.empty() && fen[0] == ' ') fen.remove_prefix(1);
+ while (!fen.empty() && fen[0] == ' ')
+ fen.remove_prefix(1);
- if (fen.empty()) return false;
+ if (fen.empty())
+ return false;
const auto params = split_string_view<6>(fen);
const auto position = params[0].has_value() ? *params[0] : "";
@@ -2948,9 +3269,11 @@ class Board {
const auto half_move = params[4].has_value() ? *params[4] : "0";
const auto full_move = params[5].has_value() ? *params[5] : "1";
- if (position.empty()) return false;
+ if (position.empty())
+ return false;
- if (move_right != "w" && move_right != "b") return false;
+ if (move_right != "w" && move_right != "b")
+ return false;
const auto half_move_opt = detail::parseStringViewToInt(half_move).value_or(0);
hfm_ = half_move_opt;
@@ -2960,36 +3283,52 @@ class Board {
plies_ = plies_ * 2 - 2;
- if (en_passant != "-") {
- if (!Square::is_valid_string_sq(en_passant)) {
+ if (en_passant != "-")
+ {
+ if (!Square::is_valid_string_sq(en_passant))
+ {
return false;
}
ep_sq_ = Square(en_passant);
- if (ep_sq_ == Square::NO_SQ) return false;
+ if (ep_sq_ == Square::NO_SQ)
+ return false;
}
stm_ = (move_right == "w") ? Color::WHITE : Color::BLACK;
- if (stm_ == Color::BLACK) {
+ if (stm_ == Color::BLACK)
+ {
plies_++;
- } else {
+ }
+ else
+ {
key_ ^= Zobrist::sideToMove();
}
auto square = 56;
- for (char curr : position) {
- if (isdigit(curr)) {
+ for (char curr : position)
+ {
+ if (isdigit(curr))
+ {
square += (curr - '0');
- } else if (curr == '/') {
+ }
+ else if (curr == '/')
+ {
square -= 16;
- } else {
+ }
+ else
+ {
auto p = Piece(std::string_view(&curr, 1));
- if (p == Piece::NONE || !Square::is_valid_sq(square) || at(square) != Piece::NONE) return false;
+ if (p == Piece::NONE || !Square::is_valid_sq(square) || at(square) != Piece::NONE)
+ return false;
- if constexpr (ctor) {
+ if constexpr (ctor)
+ {
placePieceInternal(p, Square(square));
- } else {
+ }
+ else
+ {
placePiece(p, square);
}
@@ -2998,16 +3337,20 @@ class Board {
}
}
- static const auto find_rook = [](const Board &board, CastlingRights::Side side, Color color) -> File {
+ static const auto find_rook = [](const Board& board, CastlingRights::Side side,
+ Color color) -> File {
const auto king_side = CastlingRights::Side::KING_SIDE;
const auto king_sq = board.kingSq(color);
- const auto sq_corner = Square(side == king_side ? Square::SQ_H1 : Square::SQ_A1).relative_square(color);
+ const auto sq_corner =
+ Square(side == king_side ? Square::SQ_H1 : Square::SQ_A1).relative_square(color);
const auto start = side == king_side ? king_sq + 1 : king_sq - 1;
for (Square sq = start; (side == king_side ? sq <= sq_corner : sq >= sq_corner);
- (side == king_side ? sq++ : sq--)) {
- if (board.at(sq) == PieceType::ROOK && board.at(sq).color() == color) {
+ (side == king_side ? sq++ : sq--))
+ {
+ if (board.at(sq) == PieceType::ROOK && board.at(sq).color() == color)
+ {
return sq.file();
}
}
@@ -3016,13 +3359,16 @@ class Board {
};
// Parse castling rights
- for (char i : castling) {
- if (i == '-') break;
+ for (char i : castling)
+ {
+ if (i == '-')
+ break;
const auto king_side = CastlingRights::Side::KING_SIDE;
const auto queen_side = CastlingRights::Side::QUEEN_SIDE;
- if (!chess960_) {
+ if (!chess960_)
+ {
if (i == 'K')
cr_.setCastlingRight(Color::WHITE, king_side, File::FILE_H);
else if (i == 'Q')
@@ -3041,33 +3387,47 @@ class Board {
const auto color = isupper(i) ? Color::WHITE : Color::BLACK;
const auto king_sq = kingSq(color);
- if (i == 'K' || i == 'k') {
+ if (i == 'K' || i == 'k')
+ {
auto file = find_rook(*this, king_side, color);
- if (file == File::NO_FILE) return false;
+ if (file == File::NO_FILE)
+ return false;
cr_.setCastlingRight(color, king_side, file);
- } else if (i == 'Q' || i == 'q') {
+ }
+ else if (i == 'Q' || i == 'q')
+ {
auto file = find_rook(*this, queen_side, color);
- if (file == File::NO_FILE) return false;
+ if (file == File::NO_FILE)
+ return false;
cr_.setCastlingRight(color, queen_side, file);
- } else {
+ }
+ else
+ {
const auto file = File(std::string_view(&i, 1));
- if (file == File::NO_FILE) return false;
+ if (file == File::NO_FILE)
+ return false;
const auto side = CastlingRights::closestSide(file, king_sq.file());
cr_.setCastlingRight(color, side, file);
}
}
- if (ep_sq_ != Square::NO_SQ && !((ep_sq_.rank() == Rank::RANK_3 && stm_ == Color::BLACK) ||
- (ep_sq_.rank() == Rank::RANK_6 && stm_ == Color::WHITE))) {
+ if (ep_sq_ != Square::NO_SQ
+ && !((ep_sq_.rank() == Rank::RANK_3 && stm_ == Color::BLACK)
+ || (ep_sq_.rank() == Rank::RANK_6 && stm_ == Color::WHITE)))
+ {
ep_sq_ = Square::NO_SQ;
}
- if (ep_sq_ != Square::NO_SQ) {
+ if (ep_sq_ != Square::NO_SQ)
+ {
bool valid;
- if (stm_ == Color::WHITE) {
+ if (stm_ == Color::WHITE)
+ {
valid = movegen::isEpSquareValid